Compare commits

...
25 Commits
Author SHA1 Message Date
Mervin Praison 2799304270 Release v2.2.97 2025-12-15 08:25:56 +00:00
Mervin Praison 4a85c135a6 Release v2.2.96 2025-12-15 07:57:25 +00:00
Mervin Praison cdb42a3f08 feat: add custom tools support to research command with file and built-in tool loading 2025-12-15 07:33:52 +00:00
Mervin Praison c8378118e7 docs: add query rewrite flag to research command and bump version to 2.2.94 2025-12-13 12:49:38 +00:00
Mervin Praison 0213764057 feat: add Query Rewriter Agent with multiple rewrite strategies and bump version to 0.0.166 2025-12-13 12:44:21 +00:00
Mervin Praison 2220114809 feat: add --save flag to research command for markdown output and bump version to 2.2.93 2025-12-13 11:58:36 +00:00
Mervin Praison 9fe4dbc172 chore: bump version to 2.2.92 and update praisonaiagents dependency to 0.0.165 2025-12-13 02:19:22 +00:00
Mervin Praison 180503fcd5 feat: add default research instructions to DeepResearchAgent and bump version to 0.0.165 2025-12-13 02:18:42 +00:00
Mervin Praison 0d8f936b19 chore: bump version to 2.2.91 and update praisonaiagents dependency to 0.0.164 2025-12-13 02:09:12 +00:00
Mervin Praison 8b53ebf5e3 docs: add Deep Research CLI documentation and bump version to 2.2.90 2025-12-13 01:44:52 +00:00
Mervin Praison 504c5a9759 chore: bump version to 2.2.89 and update praisonaiagents dependency to 0.0.163 2025-12-13 01:17:52 +00:00
Mervin Praison 8fef42fc03 feat: add Deep Research Agent support with OpenAI and Gemini integration 2025-12-13 01:15:07 +00:00
Mervin Praison 2f18cc1ea2 Merge branch 'main' of https://github.com/MervinPraison/PraisonAI 2025-12-13 01:13:29 +00:00
Mervin Praison ff7969cdbf docs: rewrite README from MCP SSE implementation to comprehensive PraisonAI Agents documentation 2025-12-13 01:13:28 +00:00
Mervin Praison 5fa84dc3eb Merge pull request #1084 from Dhivya-Bharathy/feature/agentic-rag
feat: Add Agentic RAG Example to Cookbooks
2025-11-03 14:14:46 +00:00
Mervin Praison 4bf8b980ed Merge pull request #1085 from Dhivya-Bharathy/feat/agentic-rag-tools
feat: Add Agentic RAG Tools Implementation
2025-11-03 14:14:24 +00:00
Mervin Praison 53e0fd19ab feat: add async run support and example scripts for multi-turn conversations 2025-08-30 11:54:59 +01:00
Dhivya-Bharathy 0cb6307d3c Add agentic_rag_gpt5 example with GPT-5 integration 2025-08-29 13:11:08 +05:30
Dhivya adce94410b Add files via upload 2025-08-29 13:01:08 +05:30
Dhivya-Bharathy 42aec561b1 Add agentic RAG Python implementation to tools 2025-08-28 14:09:09 +05:30
Dhivya acc805768d Update PraisonAI_RecipeAgent.ipynb 2025-08-28 13:00:50 +05:30
Dhivya-Bharathy 6d9fa167e3 Add agentic_rag example to cookbooks 2025-08-28 06:43:41 +00:00
Mervin Praison 9e178b70e6 chore: bump PraisonAI to v2.2.88 and update dependencies across Dockerfiles and project files 2025-08-08 19:24:43 +01:00
Mervin Praison ed406973cd refactor: optimise ChatOpenAI instantiation by using a dictionary for parameters and enforce temperature for gpt-5 models 2025-08-08 19:17:45 +01:00
Mervin Praison f91918f4f6 chore: bump PraisonAI to v2.2.87, PraisonAI Agents to v0.0.161 and increase default temperature to 1.0 2025-08-08 13:44:29 +01:00
40 changed files with 6340 additions and 305 deletions

No files matched your search

+120
View File
@@ -53,6 +53,8 @@ PraisonAI is a production-ready Multi-AI Agents framework with self-reflection,
- 🛠️ 100+ Custom Tools
- 📄 YAML Configuration
- 💯 100+ LLM Support
- 🔬 **Deep Research Agents** (OpenAI & Gemini)
- 🔄 **Query Rewriter Agent** (HyDE, Step-back, Multi-query)
## Using Python Code
@@ -96,6 +98,79 @@ Run:
python app.py
```
### 3. Deep Research Agent
Automated research with real-time streaming, web search, and citations using OpenAI or Gemini Deep Research APIs.
```python
from praisonaiagents import DeepResearchAgent
# OpenAI Deep Research
agent = DeepResearchAgent(
model="o4-mini-deep-research", # or "o3-deep-research"
verbose=True
)
result = agent.research("What are the latest AI trends in 2025?")
print(result.report)
print(f"Citations: {len(result.citations)}")
```
```python
# Gemini Deep Research
from praisonaiagents import DeepResearchAgent
agent = DeepResearchAgent(
model="deep-research-pro", # Auto-detected as Gemini
verbose=True
)
result = agent.research("Research quantum computing advances")
print(result.report)
```
**Features:**
- 🔍 Multi-provider support (OpenAI, Gemini, LiteLLM)
- 📡 Real-time streaming with reasoning summaries
- 📚 Structured citations with URLs
- 🛠️ Built-in tools: web search, code interpreter, MCP, file search
- 🔄 Automatic provider detection from model name
### 4. Query Rewriter Agent
Transform user queries to improve RAG retrieval quality using multiple strategies.
```python
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent(model="gpt-4o-mini")
# Basic - expands abbreviations, adds context
result = agent.rewrite("AI trends")
print(result.primary_query) # "What are the current trends in Artificial Intelligence?"
# HyDE - generates hypothetical document for semantic matching
result = agent.rewrite("What is quantum computing?", strategy=RewriteStrategy.HYDE)
# Step-back - generates broader context question
result = agent.rewrite("GPT-4 vs Claude 3?", strategy=RewriteStrategy.STEP_BACK)
# Sub-queries - decomposes complex questions
result = agent.rewrite("RAG setup and best embedding models?", strategy=RewriteStrategy.SUB_QUERIES)
# Contextual - resolves references using chat history
result = agent.rewrite("What about cost?", chat_history=[...])
```
**Strategies:**
- **BASIC**: Expand abbreviations, fix typos, add context
- **HYDE**: Generate hypothetical document for semantic matching
- **STEP_BACK**: Generate higher-level concept questions
- **SUB_QUERIES**: Decompose multi-part questions
- **MULTI_QUERY**: Generate multiple paraphrased versions
- **CONTEXTUAL**: Resolve references using conversation history
- **AUTO**: Automatically detect best strategy
## Using No Code
### Auto Mode:
@@ -105,6 +180,51 @@ export OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxx
praisonai --auto create a movie script about Robots in Mars
```
### Query Rewriting (works with any command):
```bash
# Rewrite query for better results (uses QueryRewriterAgent)
praisonai "AI trends" --query-rewrite
# Rewrite with search tools (agent decides when to search)
praisonai "latest developments" --query-rewrite --rewrite-tools "internet_search"
# Works with any prompt
praisonai "explain quantum computing" --query-rewrite -v
```
### Deep Research CLI:
```bash
# Default: OpenAI (o4-mini-deep-research)
praisonai research "What are the latest AI trends in 2025?"
# Use Gemini
praisonai research --model deep-research-pro "Your research query"
# Rewrite query before research
praisonai research --query-rewrite "AI trends"
# Rewrite with search tools
praisonai research --query-rewrite --rewrite-tools "internet_search" "AI trends"
# Use custom tools from file (gathers context before deep research)
praisonai research --tools tools.py "Your research query"
praisonai research -t my_tools.py "Your research query"
# Use built-in tools by name (comma-separated)
praisonai research --tools "internet_search,wiki_search" "Your query"
praisonai research -t "yfinance,calculator_tools" "Stock analysis query"
# Save output to file (output/research/{query}.md)
praisonai research --save "Your research query"
praisonai research -s "Your research query"
# Combine options
praisonai research --query-rewrite --tools tools.py --save "Your research query"
# Verbose mode (show debug logs)
praisonai research -v "Your research query"
```
## Using JavaScript Code
```bash
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
flask \
"praisonai>=2.2.86" \
"praisonai>=2.2.97" \
"praisonai[api]" \
gunicorn \
markdown
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.2.86" \
"praisonai>=2.2.97" \
"praisonai[chat]" \
"embedchain[github,youtube]"
+1 -1
View File
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.2.86" \
"praisonai>=2.2.97" \
"praisonai[ui]" \
"praisonai[chat]" \
"praisonai[realtime]" \
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.2.86" \
"praisonai>=2.2.97" \
"praisonai[ui]" \
"praisonai[crewai]"
+2 -2
View File
@@ -121,7 +121,7 @@ healthcheck:
## 📦 Package Versions
All Docker images use consistent, up-to-date versions:
- PraisonAI: `>=2.2.86`
- PraisonAI: `>=2.2.95`
- PraisonAI Agents: `>=0.0.92`
- Python: `3.11-slim`
@@ -218,7 +218,7 @@ docker-compose up -d
### Version Pinning
To use specific versions, update the Dockerfile:
```dockerfile
RUN pip install "praisonai==2.2.86" "praisonaiagents==0.0.92"
RUN pip install "praisonai==2.2.95" "praisonaiagents==0.0.92"
```
## 🌐 Production Deployment
@@ -0,0 +1,481 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "LJRJRQtFTagH"
},
"source": [
"# AI RAG Agent with Web Access using PraisonAI"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Ph4RVTBCTcmB"
},
"source": [
"This notebook demonstrates how to build a Retrieval-Augmented Generation (RAG) agent with web access using GPT-4o and PraisonAI. The agent specializes in Thai recipes and can search the web for additional information."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tMxfwPPATy_o"
},
"source": [
"This RAG agent:\n",
"* Creates an AI assistant specialized in Thai recipes and cooking\n",
"* Has access to a PDF knowledge base about Thai recipes\n",
"* Can search the web using DuckDuckGo for additional information\n",
"* Provides comprehensive answers about Thai cuisine\n",
"* Uses PraisonAI framework for agent management"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "h68oMaCITmqt"
},
"source": [
"[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Dhivya-Bharathy/PraisonAI/blob/main/examples/cookbooks/rag_examples/agentic_rag/PraisonAI_RecipeAgent.ipynb)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "cAdzoWXJUMfF"
},
"source": [
"# Dependencies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9D-2TlOrUNcu"
},
"outputs": [],
"source": [
"!pip install praisonaiagents openai requests"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "yY-4-kEIUW40"
},
"source": [
"# Set Up API Key"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "f5bhQ05yUX6J",
"outputId": "dcf9d0d9-332e-4136-9289-4c39d898005c"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your OpenAI API key: ··········\n",
"✅ API key set successfully!\n"
]
}
],
"source": [
"import os\n",
"\n",
"# Set your OpenAI API key here\n",
"os.environ['OPENAI_API_KEY'] = 'Enter your api key here'\n",
"\n",
"# Or use this method to input it securely\n",
"from getpass import getpass\n",
"api_key = getpass('Enter your OpenAI API key: ')\n",
"os.environ['OPENAI_API_KEY'] = api_key\n",
"\n",
"print(\"✅ API key set successfully!\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Eh0j-SegUi13"
},
"source": [
"# Tools"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "Z1A9oifIUkQN",
"outputId": "9be78226-36fa-43c4-865d-2f7e6e2ba9de"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Tools imported successfully!\n"
]
}
],
"source": [
"from praisonaiagents import Agent\n",
"import requests\n",
"import tempfile\n",
"from pathlib import Path\n",
"\n",
"print(\"✅ Tools imported successfully!\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "efnnREHXUnYA"
},
"source": [
"# YAML Prompt"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "kcM14-yQUqG-",
"outputId": "c5b6288d-a789-4a93-e20c-1d285370b667"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✅ Agent instructions configured!\n"
]
}
],
"source": [
"# Agent configuration and instructions\n",
"AGENT_INSTRUCTIONS = \"\"\"\n",
"You are a helpful AI assistant specialized in Thai recipes and cooking.\n",
"\n",
"You have access to a PDF knowledge base about Thai recipes from: https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf\n",
"\n",
"You can also search the web for additional information about Thai cooking, ingredients, and techniques.\n",
"\n",
"When answering questions:\n",
"1. Use your knowledge about Thai cuisine to provide helpful information\n",
"2. If needed, search the web for additional details, current information, or clarification\n",
"3. Provide comprehensive, helpful answers about Thai cuisine\n",
"4. Always be informative and helpful about Thai cooking!\n",
"\n",
"You can use the internet_search function to search the web when needed.\n",
"\n",
"Focus on providing practical cooking advice, ingredient information, and authentic Thai recipe guidance.\n",
"\"\"\"\n",
"\n",
"print(\"✅ Agent instructions configured!\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "MCBRcXFJUulY"
},
"source": [
"# Main"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "YaRLbgMmUvXv",
"outputId": "8ed8d9f8-85a7-48de-ccc6-f617cd672a85"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🤖 Thai Recipe RAG Agent created successfully!\n",
"The agent is ready to answer questions about Thai cooking.\n"
]
}
],
"source": [
"# Create the RAG agent\n",
"rag_agent = Agent(\n",
" instructions=AGENT_INSTRUCTIONS,\n",
" llm=\"gpt-4o\",\n",
" markdown=True,\n",
" verbose=True\n",
")\n",
"\n",
"print(\"🤖 Thai Recipe RAG Agent created successfully!\")\n",
"print(\"The agent is ready to answer questions about Thai cooking.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "QvZM94pGU0IX"
},
"source": [
"# Test the Agent"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000,
"referenced_widgets": [
"47739975c9f04ee5b4e69e8f445cbeda",
"08888d583cba4c01b3fdf8f30b06ca4f"
]
},
"id": "QPdrleKxU1VN",
"outputId": "a71a86cd-eff8-4309-9b50-173a30066c90"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🤔 Question: What are the essential ingredients for Thai cooking?\n"
]
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╭─ </span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8; font-weight: bold\">Agent Info</span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\"> ────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #ff9b9b; text-decoration-color: #ff9b9b; font-weight: bold\">👤 Agent:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Agent</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #b4b4b3; text-decoration-color: #b4b4b3; font-weight: bold\">Role:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Assistant</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[38;2;210;227;200m╭─\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[1;38;2;210;227;200mAgent Info\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[38;2;210;227;200m───────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;210;227;200m─╮\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;255;155;155m👤 Agent:\u001b[0m \u001b[38;2;255;229;229mAgent\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;180;180;179mRole:\u001b[0m \u001b[38;2;255;229;229mAssistant\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "47739975c9f04ee5b4e69e8f445cbeda",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
],
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
"</pre>\n"
],
"text/plain": [
"\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">Response generated in 8.4s</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[2mResponse generated in 8.4s\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭───────────────────────────────────────────────────── Task ──────────────────────────────────────────────────────╮</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> What are the essential ingredients for Thai cooking? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[36m╭─\u001b[0m\u001b[36m────────────────────────────────────────────────────\u001b[0m\u001b[36m Task \u001b[0m\u001b[36m─────────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
"\u001b[36m│\u001b[0m What are the essential ingredients for Thai cooking? \u001b[36m│\u001b[0m\n",
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭─────────────────────────────────────────────────── Response ────────────────────────────────────────────────────╮</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Thai cooking is known for its balance of five fundamental taste senses in each dish or the overall meal: sour, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> sweet, salty, bitter, and spicy. Essential ingredients that help achieve this balance include: <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 1 </span><span style=\"font-weight: bold\">Fish Sauce (Nam Pla)</span>: A salty, savory sauce made from fermented fish. It's a cornerstone of Thai cooking, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>used to add depth of flavor. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 2 </span><span style=\"font-weight: bold\">Lime Juice</span>: Used to add a fresh, tangy citrus flavor to dishes, especially in salads and some curries. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 3 </span><span style=\"font-weight: bold\">Chilies</span>: Thai cuisine often features fresh Thai bird's eye chilies for heat, as well as dried chilies for <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>certain recipes. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 4 </span><span style=\"font-weight: bold\">Lemongrass</span>: A citrusy, fragrant herb that is often used in soups, curries, and teas. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 5 </span><span style=\"font-weight: bold\">Galangal</span>: Similar to ginger, galangal has a sharp, peppery flavor and is used in soups and curries. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 6 </span><span style=\"font-weight: bold\">Kaffir Lime Leaves</span>: They add a distinct, zesty citrus aroma and flavor to Thai dishes. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 7 </span><span style=\"font-weight: bold\">Coconut Milk</span>: Adds richness and creaminess, commonly used in curries and desserts. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 8 </span><span style=\"font-weight: bold\">Palm Sugar</span>: Used as a sweetener, palm sugar has a nuanced flavor, unlike regular sugar. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 9 </span><span style=\"font-weight: bold\">Tamarind Paste</span>: Provides a sour element to many dishes, particularly pad Thai and some sauces. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 10 </span><span style=\"font-weight: bold\">Thai Basil</span>: Adds a spicy, peppery flavor, different from the sweet basil used in Western cooking. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 11 </span><span style=\"font-weight: bold\">Coriander (Cilantro)</span>: Used as a garnish and for its fresh, citrusy leaves and roots, which add depth to <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>sauces and stocks. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> 12 </span><span style=\"font-weight: bold\">Shrimp Paste</span>: A very pungent paste made from fermented shrimp, used sparingly to enrich the flavor of <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>dishes. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> These ingredients are commonly used in combination to create the complex and rich flavors characteristic of <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Thai cuisine. Fresh and high-quality versions of these ingredients contribute significantly to the authenticity <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> of Thai dishes. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────────\u001b[0m\u001b[36m Response \u001b[0m\u001b[36m───────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
"\u001b[36m│\u001b[0m Thai cooking is known for its balance of five fundamental taste senses in each dish or the overall meal: sour, \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m sweet, salty, bitter, and spicy. Essential ingredients that help achieve this balance include: \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 1 \u001b[0m\u001b[1mFish Sauce (Nam Pla)\u001b[0m: A salty, savory sauce made from fermented fish. It's a cornerstone of Thai cooking, \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mused to add depth of flavor. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 2 \u001b[0m\u001b[1mLime Juice\u001b[0m: Used to add a fresh, tangy citrus flavor to dishes, especially in salads and some curries. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 3 \u001b[0m\u001b[1mChilies\u001b[0m: Thai cuisine often features fresh Thai bird's eye chilies for heat, as well as dried chilies for \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mcertain recipes. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 4 \u001b[0m\u001b[1mLemongrass\u001b[0m: A citrusy, fragrant herb that is often used in soups, curries, and teas. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 5 \u001b[0m\u001b[1mGalangal\u001b[0m: Similar to ginger, galangal has a sharp, peppery flavor and is used in soups and curries. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 6 \u001b[0m\u001b[1mKaffir Lime Leaves\u001b[0m: They add a distinct, zesty citrus aroma and flavor to Thai dishes. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 7 \u001b[0m\u001b[1mCoconut Milk\u001b[0m: Adds richness and creaminess, commonly used in curries and desserts. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 8 \u001b[0m\u001b[1mPalm Sugar\u001b[0m: Used as a sweetener, palm sugar has a nuanced flavor, unlike regular sugar. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 9 \u001b[0m\u001b[1mTamarind Paste\u001b[0m: Provides a sour element to many dishes, particularly pad Thai and some sauces. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 10 \u001b[0m\u001b[1mThai Basil\u001b[0m: Adds a spicy, peppery flavor, different from the sweet basil used in Western cooking. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 11 \u001b[0m\u001b[1mCoriander (Cilantro)\u001b[0m: Used as a garnish and for its fresh, citrusy leaves and roots, which add depth to \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0msauces and stocks. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m 12 \u001b[0m\u001b[1mShrimp Paste\u001b[0m: A very pungent paste made from fermented shrimp, used sparingly to enrich the flavor of \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mdishes. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m These ingredients are commonly used in combination to create the complex and rich flavors characteristic of \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m Thai cuisine. Fresh and high-quality versions of these ingredients contribute significantly to the authenticity \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m of Thai dishes. \u001b[36m│\u001b[0m\n",
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"�� Answer: Thai cooking is known for its balance of five fundamental taste senses in each dish or the overall meal: sour, sweet, salty, bitter, and spicy. Essential ingredients that help achieve this balance include:\n",
"\n",
"1. **Fish Sauce (Nam Pla)**: A salty, savory sauce made from fermented fish. It's a cornerstone of Thai cooking, used to add depth of flavor.\n",
"\n",
"2. **Lime Juice**: Used to add a fresh, tangy citrus flavor to dishes, especially in salads and some curries.\n",
"\n",
"3. **Chilies**: Thai cuisine often features fresh Thai bird's eye chilies for heat, as well as dried chilies for certain recipes.\n",
"\n",
"4. **Lemongrass**: A citrusy, fragrant herb that is often used in soups, curries, and teas.\n",
"\n",
"5. **Galangal**: Similar to ginger, galangal has a sharp, peppery flavor and is used in soups and curries.\n",
"\n",
"6. **Kaffir Lime Leaves**: They add a distinct, zesty citrus aroma and flavor to Thai dishes.\n",
"\n",
"7. **Coconut Milk**: Adds richness and creaminess, commonly used in curries and desserts.\n",
"\n",
"8. **Palm Sugar**: Used as a sweetener, palm sugar has a nuanced flavor, unlike regular sugar.\n",
"\n",
"9. **Tamarind Paste**: Provides a sour element to many dishes, particularly pad Thai and some sauces.\n",
"\n",
"10. **Thai Basil**: Adds a spicy, peppery flavor, different from the sweet basil used in Western cooking.\n",
"\n",
"11. **Coriander (Cilantro)**: Used as a garnish and for its fresh, citrusy leaves and roots, which add depth to sauces and stocks.\n",
"\n",
"12. **Shrimp Paste**: A very pungent paste made from fermented shrimp, used sparingly to enrich the flavor of dishes.\n",
"\n",
"These ingredients are commonly used in combination to create the complex and rich flavors characteristic of Thai cuisine. Fresh and high-quality versions of these ingredients contribute significantly to the authenticity of Thai dishes.\n"
]
}
],
"source": [
"# Test question 1: Basic Thai cooking\n",
"question1 = \"What are the essential ingredients for Thai cooking?\"\n",
"print(f\"🤔 Question: {question1}\")\n",
"\n",
"try:\n",
" response1 = rag_agent.start(question1)\n",
" print(f\"�� Answer: {response1}\")\n",
"except Exception as e:\n",
" print(f\"❌ Error: {e}\")"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
@@ -0,0 +1,556 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "EA8l4cSVl3Lx"
},
"source": [
"# Agentic RAG with GPT-5 - Colab Notebook"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "I-8nOxJ2l7nO"
},
"source": [
"This Colab notebook sets up a Streamlit app using PraisonAI Agents framework.\n",
"It allows you to interact with an AI agent powered by GPT-5 for Q&A.\n",
"Currently, the knowledge base functionality is disabled due to compatibility issues."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "g5I1tMkxmDQe"
},
"source": [
"- GPT-5 Integration (via OpenAI API)\n",
"- Streamlit Web App\n",
"- Agent Framework: PraisonAI Agents\n",
"- Markdown-formatted responses"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "yeEno7U0q2U_"
},
"source": [
"[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Dhivya-Bharathy/PraisonAI/blob/main/examples/cookbooks/Qwen2.5_InstructionAgent.ipynb)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WV2GnzZCmGBR"
},
"source": [
"# Dependencies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "20wAadXemJ0k"
},
"outputs": [],
"source": [
"!pip install praisonaiagents python-dotenv streamlit"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "l71uCRarndvy"
},
"source": [
"# Set API Key"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"id": "brfc-ZZKnfre"
},
"outputs": [],
"source": [
"import os\n",
"from dotenv import load_dotenv\n",
"\n",
"load_dotenv()\n",
"\n",
"OPENAI_API_KEY = \"Enter your api key here\"\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "d1fGzyQCn1aQ"
},
"source": [
"# Tools and Imports"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"id": "GcNPLkZXntIS"
},
"outputs": [],
"source": [
"import streamlit as st\n",
"from praisonaiagents import Agent\n",
"\n",
"# YAML Prompt Configuration\n",
"agent_config = {\n",
" \"name\": \"Knowledge Agent\",\n",
" \"instructions\": [\n",
" \"You are a helpful AI assistant. Answer questions based on your general knowledge.\",\n",
" \"Provide clear, well-structured answers in markdown format.\",\n",
" \"Use proper markdown formatting with headers, lists, and emphasis where appropriate.\",\n",
" \"Structure your response with clear sections and bullet points when helpful.\",\n",
" ],\n",
" \"llm\": \"gpt-5-nano\",\n",
" \"markdown\": True,\n",
" \"verbose\": True\n",
"}\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "jkmrh0gIn_4a"
},
"source": [
"# Initialize Agent"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"id": "qaJvf8RyoAsB"
},
"outputs": [],
"source": [
"def create_agent():\n",
" \"\"\"Create an agent with reasoning capabilities\"\"\"\n",
" return Agent(\n",
" name=agent_config[\"name\"],\n",
" instructions=agent_config[\"instructions\"],\n",
" llm=agent_config[\"llm\"],\n",
" markdown=agent_config[\"markdown\"],\n",
" verbose=agent_config[\"verbose\"]\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "kvGJh3bbqTmh"
},
"source": [
"# Main Function"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000,
"referenced_widgets": [
"ad296d97510246de8eb0138ce8a8a166",
"f6e502b3dca442f0ae6c5739f5a6d159"
]
},
"id": "_QyxzqKKqUrW",
"outputId": "97be7e02-b034-4004-e9e3-56337e3f2887"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"�� Initializing Agentic RAG with GPT-5...\n",
"📚 Loading agent...\n",
"✅ Agent loaded successfully!\n",
"\n",
"🎯 Example queries you can try:\n",
"1. What is PraisonAI and how do Agents work?\n",
"2. What are Teams in PraisonAI and how do they work?\n",
"3. Give me a step-by-step guide to building a RAG system.\n",
"4. What are AI Agents?\n",
"\n",
"============================================================\n",
"\n",
"🤔 Enter your question (or 'quit' to exit):\n",
"> What is PraisonAI and how do Agents work?\n",
"🔍 Processing your question...\n"
]
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╭─ </span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8; font-weight: bold\">Agent Info</span><span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\"> ────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #ff9b9b; text-decoration-color: #ff9b9b; font-weight: bold\">👤 Agent:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Knowledge Agent</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #b4b4b3; text-decoration-color: #b4b4b3; font-weight: bold\">Role:</span> <span style=\"color: #ffe5e5; text-decoration-color: #ffe5e5\">Assistant</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span> <span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">│</span>\n",
"<span style=\"color: #d2e3c8; text-decoration-color: #d2e3c8\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[38;2;210;227;200m╭─\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[1;38;2;210;227;200mAgent Info\u001b[0m\u001b[38;2;210;227;200m \u001b[0m\u001b[38;2;210;227;200m───────────────────────────────────────────────────────────────────────────────────────────────────\u001b[0m\u001b[38;2;210;227;200m─╮\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;255;155;155m👤 Agent:\u001b[0m \u001b[38;2;255;229;229mKnowledge Agent\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[1;38;2;180;180;179mRole:\u001b[0m \u001b[38;2;255;229;229mAssistant\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m│\u001b[0m \u001b[38;2;210;227;200m│\u001b[0m\n",
"\u001b[38;2;210;227;200m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "ad296d97510246de8eb0138ce8a8a166",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
],
"text/plain": []
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
"</pre>\n"
],
"text/plain": [
"\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">Response generated in 9.4s</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[2mResponse generated in 9.4s\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭───────────────────────────────────────────────────── Task ──────────────────────────────────────────────────────╮</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> What is PraisonAI and how do Agents work? <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[36m╭─\u001b[0m\u001b[36m────────────────────────────────────────────────────\u001b[0m\u001b[36m Task \u001b[0m\u001b[36m─────────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
"\u001b[36m│\u001b[0m What is PraisonAI and how do Agents work? \u001b[36m│\u001b[0m\n",
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">╭─────────────────────────────────────────────────── Response ────────────────────────────────────────────────────╮</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┃ <span style=\"font-weight: bold\">What is PraisonAI?</span> ┃ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> PraisonAI is a platform designed to leverage artificial intelligence to enhance personal and business <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> productivity. It typically involves developing AI models that can assist in various tasks, automate processes, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> and provide insights based on data analysis. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">Key Features of PraisonAI</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Task Automation</span>: Automates repetitive tasks, allowing users to focus on more strategic activities. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Data Insights</span>: Analyzes large sets of data to provide actionable insights. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Natural Language Processing</span>: Enables users to interact with the AI through natural language, making it <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>user-friendly. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Customizable Solutions</span>: Tailors AI applications to meet specific user needs across various industries. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┃ <span style=\"font-weight: bold\">How Do Agents Work in PraisonAI?</span> ┃ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> Agents in PraisonAI refer to autonomous or semi-autonomous AI systems that perform designated tasks or <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> functions. Here’s how they typically operate: <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">1. Types of Agents</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Reactive Agents</span>: Respond to the current environment without internal memory. They act solely based on <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>current inputs. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Deliberative Agents</span>: Have a model of their environment, plan their actions, and retain memories of past <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>interactions. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Learning Agents</span>: Improve their performance over time through experience, adapting to new information. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">2. Functionality of Agents</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Task Execution</span>: Agents can carry out specific tasks as programmed, such as scheduling, data entry, or <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>customer support. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Interaction</span>: They often interact with users through chat interfaces or APIs, providing a seamless user <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>experience. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Integration</span>: Can be integrated with other systems or software to enhance functionality, such as CRM systems, <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>databases, or other AI tools. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Continuous Learning</span>: Agents may utilize machine learning algorithms to adapt and evolve based on user <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> </span>interactions and data received. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">3. Benefits of Using Agents</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Increased Efficiency</span>: Automate routine tasks to reduce workload. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">24/7 Availability</span>: Provide consistent support and functionality without downtime. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Scalability</span>: Easily scale operations by deploying more agents as needed. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\"> • </span><span style=\"font-weight: bold\">Data-Driven Decisions</span>: Use data insights to inform strategy and operations. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"font-weight: bold; text-decoration: underline\">Conclusion</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> PraisonAI represents a robust platform for enhancing productivity through AI, with agents serving as the heart <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> of this solution, performing various tasks and supporting users in achieving their goals efficiently. Whether <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> they are simple reactive agents or complex learning entities, their design focuses on making operations <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">│</span> smoother and more effective. <span style=\"color: #008080; text-decoration-color: #008080\">│</span>\n",
"<span style=\"color: #008080; text-decoration-color: #008080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[36m╭─\u001b[0m\u001b[36m──────────────────────────────────────────────────\u001b[0m\u001b[36m Response \u001b[0m\u001b[36m───────────────────────────────────────────────────\u001b[0m\u001b[36m─╮\u001b[0m\n",
"\u001b[36m│\u001b[0m ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m ┃ \u001b[1mWhat is PraisonAI?\u001b[0m ┃ \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m PraisonAI is a platform designed to leverage artificial intelligence to enhance personal and business \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m productivity. It typically involves developing AI models that can assist in various tasks, automate processes, \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m and provide insights based on data analysis. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;4mKey Features of PraisonAI\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mTask Automation\u001b[0m: Automates repetitive tasks, allowing users to focus on more strategic activities. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mData Insights\u001b[0m: Analyzes large sets of data to provide actionable insights. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mNatural Language Processing\u001b[0m: Enables users to interact with the AI through natural language, making it \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0muser-friendly. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mCustomizable Solutions\u001b[0m: Tailors AI applications to meet specific user needs across various industries. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m ┃ \u001b[1mHow Do Agents Work in PraisonAI?\u001b[0m ┃ \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m Agents in PraisonAI refer to autonomous or semi-autonomous AI systems that perform designated tasks or \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m functions. Here’s how they typically operate: \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;4m1. \u001b[0m\u001b[1;4mTypes of Agents\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mReactive Agents\u001b[0m: Respond to the current environment without internal memory. They act solely based on \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mcurrent inputs. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mDeliberative Agents\u001b[0m: Have a model of their environment, plan their actions, and retain memories of past \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0minteractions. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mLearning Agents\u001b[0m: Improve their performance over time through experience, adapting to new information. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;4m2. \u001b[0m\u001b[1;4mFunctionality of Agents\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mTask Execution\u001b[0m: Agents can carry out specific tasks as programmed, such as scheduling, data entry, or \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mcustomer support. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mInteraction\u001b[0m: They often interact with users through chat interfaces or APIs, providing a seamless user \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mexperience. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mIntegration\u001b[0m: Can be integrated with other systems or software to enhance functionality, such as CRM systems, \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0mdatabases, or other AI tools. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mContinuous Learning\u001b[0m: Agents may utilize machine learning algorithms to adapt and evolve based on user \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m \u001b[0minteractions and data received. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;4m3. \u001b[0m\u001b[1;4mBenefits of Using Agents\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mIncreased Efficiency\u001b[0m: Automate routine tasks to reduce workload. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1m24/7 Availability\u001b[0m: Provide consistent support and functionality without downtime. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mScalability\u001b[0m: Easily scale operations by deploying more agents as needed. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;33m • \u001b[0m\u001b[1mData-Driven Decisions\u001b[0m: Use data insights to inform strategy and operations. \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[1;4mConclusion\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m PraisonAI represents a robust platform for enhancing productivity through AI, with agents serving as the heart \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m of this solution, performing various tasks and supporting users in achieving their goals efficiently. Whether \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m they are simple reactive agents or complex learning entities, their design focuses on making operations \u001b[36m│\u001b[0m\n",
"\u001b[36m│\u001b[0m smoother and more effective. \u001b[36m│\u001b[0m\n",
"\u001b[36m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"💡 Answer:\n",
"========================================\n",
"# What is PraisonAI?\n",
"\n",
"PraisonAI is a platform designed to leverage artificial intelligence to enhance personal and business productivity. It typically involves developing AI models that can assist in various tasks, automate processes, and provide insights based on data analysis.\n",
"\n",
"## Key Features of PraisonAI\n",
"\n",
"- **Task Automation**: Automates repetitive tasks, allowing users to focus on more strategic activities.\n",
"- **Data Insights**: Analyzes large sets of data to provide actionable insights.\n",
"- **Natural Language Processing**: Enables users to interact with the AI through natural language, making it user-friendly.\n",
"- **Customizable Solutions**: Tailors AI applications to meet specific user needs across various industries.\n",
"\n",
"# How Do Agents Work in PraisonAI?\n",
"\n",
"Agents in PraisonAI refer to autonomous or semi-autonomous AI systems that perform designated tasks or functions. Here’s how they typically operate:\n",
"\n",
"## 1. **Types of Agents**\n",
"\n",
"- **Reactive Agents**: Respond to the current environment without internal memory. They act solely based on current inputs.\n",
"- **Deliberative Agents**: Have a model of their environment, plan their actions, and retain memories of past interactions.\n",
"- **Learning Agents**: Improve their performance over time through experience, adapting to new information.\n",
"\n",
"## 2. **Functionality of Agents**\n",
"\n",
"- **Task Execution**: Agents can carry out specific tasks as programmed, such as scheduling, data entry, or customer support.\n",
"- **Interaction**: They often interact with users through chat interfaces or APIs, providing a seamless user experience.\n",
"- **Integration**: Can be integrated with other systems or software to enhance functionality, such as CRM systems, databases, or other AI tools.\n",
"- **Continuous Learning**: Agents may utilize machine learning algorithms to adapt and evolve based on user interactions and data received.\n",
"\n",
"## 3. **Benefits of Using Agents**\n",
"\n",
"- **Increased Efficiency**: Automate routine tasks to reduce workload.\n",
"- **24/7 Availability**: Provide consistent support and functionality without downtime.\n",
"- **Scalability**: Easily scale operations by deploying more agents as needed.\n",
"- **Data-Driven Decisions**: Use data insights to inform strategy and operations.\n",
"\n",
"## Conclusion\n",
"\n",
"PraisonAI represents a robust platform for enhancing productivity through AI, with agents serving as the heart of this solution, performing various tasks and supporting users in achieving their goals efficiently. Whether they are simple reactive agents or complex learning entities, their design focuses on making operations smoother and more effective.\n",
"========================================\n",
"\n",
"🤔 Enter your question (or 'quit' to exit):\n",
"> quit\n",
"👋 Goodbye!\n"
]
}
],
"source": [
"def main():\n",
" print(\"�� Initializing Agentic RAG with GPT-5...\")\n",
"\n",
" # Check if API key is set\n",
" if not OPENAI_API_KEY or OPENAI_API_KEY == \"your_openai_api_key_here\":\n",
" print(\"❌ Please set your OpenAI API key first!\")\n",
" print(\"�� Get your key from: https://platform.openai.com/\")\n",
" return\n",
"\n",
" try:\n",
" # Create agent\n",
" print(\"📚 Loading agent...\")\n",
" agent = create_agent()\n",
" print(\"✅ Agent loaded successfully!\")\n",
"\n",
" # Example queries\n",
" example_queries = [\n",
" \"What is PraisonAI and how do Agents work?\",\n",
" \"What are Teams in PraisonAI and how do they work?\",\n",
" \"Give me a step-by-step guide to building a RAG system.\",\n",
" \"What are AI Agents?\"\n",
" ]\n",
"\n",
" print(\"\\n🎯 Example queries you can try:\")\n",
" for i, query in enumerate(example_queries, 1):\n",
" print(f\"{i}. {query}\")\n",
"\n",
" print(\"\\n\" + \"=\"*60)\n",
"\n",
" # Interactive query loop\n",
" while True:\n",
" print(\"\\n🤔 Enter your question (or 'quit' to exit):\")\n",
" user_query = input(\"> \")\n",
"\n",
" if user_query.lower() in ['quit', 'exit', 'q']:\n",
" print(\"👋 Goodbye!\")\n",
" break\n",
"\n",
" if user_query.strip():\n",
" print(\"🔍 Processing your question...\")\n",
" try:\n",
" response = agent.start(user_query)\n",
" print(\"\\n💡 Answer:\")\n",
" print(\"=\"*40)\n",
" print(response)\n",
" print(\"=\"*40)\n",
" except Exception as e:\n",
" print(f\"❌ Error: {str(e)}\")\n",
" print(f\"🔍 Error type: {type(e).__name__}\")\n",
" print(\"💡 This might be due to API issues or model access problems.\")\n",
" else:\n",
" print(\"❌ Please enter a valid question.\")\n",
"\n",
" except Exception as e:\n",
" print(f\"❌ Failed to initialize agent: {str(e)}\")\n",
" print(\"�� Make sure your API key is correct and you have sufficient credits.\")\n",
"\n",
"# Run the main function\n",
"if __name__ == \"__main__\":\n",
" main()"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
@@ -0,0 +1,44 @@
from praisonaiagents import Agent
import os
# Set OpenAI API key if not already set
if not os.getenv("OPENAI_API_KEY"):
print("Please set your OpenAI API key: export OPENAI_API_KEY='your-api-key-here'")
exit(1)
# Create the RAG agent with web search capabilities
rag_agent = Agent(
instructions="""You are a helpful AI assistant specialized in Thai recipes and cooking.
You have access to a PDF knowledge base about Thai recipes from: https://phi-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf
You can also search the web for additional information about Thai cooking, ingredients, and techniques.
When answering questions:
1. Use your knowledge about Thai cuisine to provide helpful information
2. If needed, search the web for additional details, current information, or clarification
3. Provide comprehensive, helpful answers about Thai cuisine
4. Always be informative and helpful about Thai cooking!
You can use the internet_search function to search the web when needed.""",
llm="gpt-4o",
markdown=True,
verbose=True
)
if __name__ == "__main__":
print("🤖 Thai Recipe RAG Agent is ready!")
print("Ask me anything about Thai recipes or cooking!")
print("Type 'quit' to exit.\n")
while True:
user_input = input("You: ")
if user_input.lower() in ['quit', 'exit', 'bye']:
print("👋 Goodbye! Happy cooking!")
break
try:
response = rag_agent.start(user_input)
print(f"\n🤖 Assistant: {response}\n")
except Exception as e:
print(f"❌ Error: {e}\n")
@@ -0,0 +1,154 @@
# 🧠 Agentic RAG with GPT-5
An agentic RAG application built with the PraisonAI Agents framework, featuring GPT-5 and built-in vector search for efficient knowledge retrieval and question answering.
## ✨ Features
- **🤖 GPT-5**: Latest OpenAI model for intelligent responses
- **🗄️ Built-in Vector Search**: ChromaDB integration for fast similarity search
- **🔍 Agentic RAG**: Intelligent retrieval augmented generation
- **📝 Markdown Formatting**: Beautiful, structured responses
- **🌐 Dynamic Knowledge**: Add URLs to expand knowledge base
- **⚡ Real-time Responses**: Fast answer generation- **🎯 Clean Interface**: Simplified UI without configuration complexity
## 🚀 Quick Start
### Prerequisites
- Python 3.11+
- OpenAI API key with GPT-5 access
### Installation
1. **Clone and navigate to the project**
```bash
cd rag_examples/agentic_rag_gpt5
```
2. **Install dependencies**
```bash
pip install -r requirements.txt
```
3. **Set up your OpenAI API key**
```bash
export OPENAI_API_KEY="your-api-key-here"
```
Or create a `.env` file:
```
OPENAI_API_KEY=your-api-key-here
```
4. **Run the application**
```bash
streamlit run agentic_rag_gpt5.py
```
## 🎯 How to Use
1. **Enter your OpenAI API key** in the sidebar
2. **Add knowledge sources** by entering URLs in the sidebar
3. **Ask questions** using the text area or suggested prompts
4. **Get answers** with markdown formatting
### Suggested Questions
- **"What is PraisonAI?"** - Learn about the PraisonAI Agents framework
- **"Teams in PraisonAI"** - Understand how teams work in PraisonAI
- **"Build RAG system"** - Get a step-by-step guide to building RAG systems
## 🏗️ Architecture
### Core Components
- **`Agent`**: PraisonAI Agents framework for intelligent Q&A
- **`knowledge`**: Built-in knowledge base that handles URLs and documents
- **`llm`**: OpenAI GPT-5-nano for generating responses
- **Built-in Vector Search**: Automatic similarity search without external setup
### Data Flow
1. **Knowledge Loading**: URLs are processed and stored in the built-in vector database
2. **Vector Search**: OpenAI embeddings enable semantic search
3. **Response Generation**: GPT-5-nano processes information and generates answers
4. **Formatted Output**: Markdown-formatted responses
## 🔧 Configuration
### Database Settings
- **Vector DB**: Built-in vector database with automatic indexing
- **Storage**: Local storage managed by PraisonAI Agents
- **Search**: Automatic similarity search
### Model Configuration
- **LLM**: OpenAI GPT-5-nano
- **Embeddings**: Automatic handling by PraisonAI Agents
- **Vector Store**: Built-in with automatic document processing
## 📚 Knowledge Management
### Adding Sources
- Use the sidebar to add new URLs
- Sources are automatically processed and indexed
- Current sources are displayed as numbered list
### Default Knowledge
- Starts with PraisonAI documentation: `https://docs.praisonai.com/introduction/agents.md`
- Expandable with any web-based documentation
## 🎨 UI Features
### Sidebar
- **API Key Management**: Secure input for OpenAI credentials
- **URL Addition**: Dynamic knowledge base expansion
- **Current Sources**: Numbered list of loaded URLs
### Main Interface
- **Suggested Prompts**: Quick access to common questions
- **Query Input**: Large text area for custom questions
- **Fast Responses**: Quick answer generation
- **Markdown Rendering**: Beautiful formatted responses
## 🛠️ Technical Details
### Dependencies
```
streamlit>=1.28.0
praisonaiagents>=0.1.0
openai>=1.0.0
python-dotenv>=1.0.0
```
### Key Features
- **Built-in Knowledge Base**: Automatic document processing and indexing
- **Vector Search**: Efficient similarity search with built-in database
- **Caching**: Efficient resource loading with Streamlit caching
- **Error Handling**: Graceful handling of API and processing errors
## 🔍 Troubleshooting
### Common Issues
**Knowledge base not loading**
- Check OpenAI API key is valid
- Ensure URLs are accessible
- Verify internet connection
**Agent initialization errors**
- Check if PraisonAI Agents is properly installed
- Verify OpenAI API key has sufficient credits
- Ensure Python version is 3.11+
### Performance Tips
- **Cache Resources**: Knowledge base and agent are cached for efficiency
- **Built-in Vector Search**: Fast similarity search without external setup
- **Local Storage**: Optimized local storage for optimal performance
## 🎯 Use Cases
- **Documentation Q&A**: Ask questions about technical documentation
- **Research Assistant**: Get answers from multiple knowledge sources
- **Learning Tool**: Interactive exploration of complex topics
- **Content Discovery**: Find relevant information across multiple sources
**Built with ❤️ using PraisonAI Agents and GPT-5**
@@ -0,0 +1,201 @@
import streamlit as st
import os
from praisonaiagents import Agent
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Page configuration
st.set_page_config(
page_title="Agentic RAG with GPT-5",
page_icon="🧠",
layout="wide"
)
# Main title and description
st.title("🧠 Agentic RAG with GPT-5")
st.markdown("""
This app demonstrates an intelligent AI agent that:
1. **Answers** your questions clearly and concisely using GPT-5
⚠️ **Note**: Knowledge base functionality is temporarily disabled due to a compatibility issue with the current version of PraisonAI Agents.
Enter your OpenAI API key in the sidebar to get started!
""")
# Sidebar for API key and settings
with st.sidebar:
st.header("🔧 Configuration")
# OpenAI API Key
openai_key = st.text_input(
"OpenAI API Key",
type="password",
value=os.getenv("OPENAI_API_KEY", ""),
help="Get your key from https://platform.openai.com/"
)
# Add URLs to knowledge base
st.subheader("🌐 Add Knowledge Sources")
st.info("⚠️ Knowledge base functionality is temporarily disabled due to compatibility issues.")
new_url = st.text_input(
"Add URL",
placeholder="https://docs.praisonai.com/introduction",
help="Enter a URL to add to the knowledge base (currently disabled)"
)
if st.button("➕ Add URL", type="primary", disabled=True):
st.info("Knowledge base functionality is temporarily disabled.")
# Check if API key is provided
if openai_key:
# Initialize knowledge base (cached to avoid reloading)
@st.cache_resource(show_spinner="📚 Loading knowledge base...")
def load_knowledge() -> list:
"""Load and initialize the knowledge base with default URL"""
return ["https://docs.praisonai.com/introduction/agents.md"] # Default URL
# Initialize agent (cached to avoid reloading)
@st.cache_resource(show_spinner="🤖 Loading agent...")
def load_agent(_knowledge: list) -> Agent:
"""Create an agent with reasoning capabilities"""
# Note: Temporarily removed knowledge parameter to avoid rerank error
# TODO: Re-enable when PraisonAI Agents knowledge issue is resolved
return Agent(
name="Knowledge Agent",
instructions=[
"You are a helpful AI assistant. Answer questions based on your general knowledge.",
"Provide clear, well-structured answers in markdown format.",
"Use proper markdown formatting with headers, lists, and emphasis where appropriate.",
"Structure your response with clear sections and bullet points when helpful.",
],
llm="gpt-5-nano
markdown=True,
verbose=True
)
# Load knowledge and agent
knowledge = load_knowledge()
agent = load_agent(knowledge)
# Display current URLs in knowledge base
if knowledge:
st.sidebar.subheader("📚 Current Knowledge Sources")
for i, url in enumerate(knowledge, 1):
st.sidebar.markdown(f"{i}. {url}")
# Handle URL additions
if hasattr(st.session_state, 'urls_to_add') and st.session_state.urls_to_add:
with st.spinner("📥 Loading new documents..."):
knowledge.append(st.session_state.urls_to_add)
# Reinitialize agent with new knowledge
agent = load_agent(knowledge)
st.success(f"✅ Added: {st.session_state.urls_to_add}")
del st.session_state.urls_to_add
st.rerun()
# Main query section
st.divider()
st.subheader("🤔 Ask a Question")
# Suggested prompts
st.markdown("**Try these prompts:**")
col1, col2, col3 = st.columns(3)
with col1:
if st.button("What is PraisonAI?", use_container_width=True):
st.session_state.query = "What is PraisonAI and how do Agents work?"
with col2:
if st.button("Teams in PraisonAI", use_container_width=True):
st.session_state.query = "What are Teams in PraisonAI and how do they work?"
with col3:
if st.button("Build RAG system", use_container_width=True):
st.session_state.query = "Give me a step-by-step guide to building a RAG system."
# Query input
query = st.text_area(
"Your question:",
value=st.session_state.get("query", "What are AI Agents?"),
height=100,
help="Ask anything about the loaded knowledge sources"
)
# Run button
if st.button("🚀 Get Answer", type="primary"):
if query:
# Create container for answer
st.markdown("### 💡 Answer")
answer_container = st.container()
answer_placeholder = answer_container.empty()
# Get the agent's response
with st.spinner("🔍 Searching and generating answer..."):
try:
st.info("🤖 Agent is processing your question...")
response = agent.start(query)
answer_placeholder.markdown(
response,
unsafe_allow_html=True
)
except Exception as e:
st.error(f"Error getting response: {str(e)}")
st.error(f"Error type: {type(e).__name__}")
st.error(f"Full error details: {repr(e)}")
# Try to provide a helpful response
answer_placeholder.markdown("""
**⚠️ Error occurred while processing your question.**
This might be due to:
- Knowledge base configuration issues
- Model access problems
- Network connectivity issues
Please try again or check your OpenAI API key.
""")
else:
st.error("Please enter a question")
else:
# Show instructions if API key is missing
st.info("""
👋 **Welcome! To use this app, you need:**
- **OpenAI API Key** (set it in the sidebar)
- Sign up at [platform.openai.com](https://platform.openai.com/)
- Generate a new API key
Once you enter the key, the app will load the knowledge base and agent.
""")
# Footer with explanation
st.divider()
with st.expander("📖 How This Works"):
st.markdown("""
**This app uses the PraisonAI Agents framework to create an intelligent Q&A system:**
⚠️ **Current Status**: Knowledge base functionality is temporarily disabled due to compatibility issues with the current version of PraisonAI Agents (v0.0.157).
**What Works Now:**
1. **GPT-5 Integration**: OpenAI's GPT-5 model for generating intelligent responses
2. **Markdown Formatting**: Beautiful, structured responses
3. **Agent Framework**: PraisonAI Agents for orchestration
**What's Temporarily Disabled:**
- URL-based knowledge base
- Vector search and retrieval
- Document processing
**Key Components:**
- `Agent`: PraisonAI Agents framework for creating intelligent agents
- `llm`: OpenAI GPT-5-nano for generating responses
**Why PraisonAI Agents?**
- Easy-to-use agent framework
- Built-in error handling
- Clean API design
- Perfect for prototyping and production applications
**Next Steps:**
- Monitor PraisonAI Agents updates for knowledge base fixes
- Re-enable knowledge functionality when compatible version is available
""")
+571 -54
View File
@@ -1,83 +1,600 @@
# MCP SSE Server and Client Implementation
# PraisonAI Agents
This project demonstrates a working pattern for SSE-based MCP (Model Context Protocol) servers and clients. It consists of three main components:
A powerful Python framework for building AI agents with self-reflection, tool use, and multi-agent orchestration capabilities.
1. **server.py**: An SSE-based MCP server that provides simple tools
2. **client.py**: A standalone client that connects to the server and uses its tools with Claude
3. **mcp-sse.py**: A client using praisonaiagents that connects to the server and uses its tools with OpenAI
[![PyPI version](https://badge.fury.io/py/praisonaiagents.svg)](https://badge.fury.io/py/praisonaiagents)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
## Tools Provided by the Server
The server implements two simple tools:
- **get_greeting**: Returns a personalized greeting for a given name
- **get_weather**: Returns simulated weather data for a given city
## Setup and Usage
### Prerequisites
Make sure you have the required packages installed:
## Installation
```bash
pip install praisonaiagents mcp httpx starlette uvicorn anthropic python-dotenv
# Basic installation
pip install praisonaiagents
# With all features
pip install "praisonaiagents[all]"
# Specific features
pip install "praisonaiagents[memory]" # Memory support
pip install "praisonaiagents[knowledge]" # Knowledge base
pip install "praisonaiagents[mcp]" # Model Context Protocol
pip install "praisonaiagents[llm]" # LiteLLM support
pip install "praisonaiagents[mongodb]" # MongoDB integration
```
### Running the Server
## Quick Start
First, start the MCP SSE server:
### Basic Agent
```python
from praisonaiagents import Agent
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant.",
model="gpt-4o-mini"
)
response = agent.chat("What is the capital of France?")
print(response)
```
### Agent with Tools
```python
from praisonaiagents import Agent
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Weather in {city}: Sunny, 22°C"
agent = Agent(
name="Weather Agent",
instructions="You help users check the weather.",
tools=[get_weather]
)
response = agent.chat("What's the weather in Paris?")
```
### Multi-Agent Workflow
```python
from praisonaiagents import Agent, Task, PraisonAIAgents
# Define agents
researcher = Agent(name="Researcher", instructions="Research topics thoroughly")
writer = Agent(name="Writer", instructions="Write clear, engaging content")
# Define tasks
research_task = Task(
description="Research AI trends in 2025",
agent=researcher,
expected_output="Research findings"
)
write_task = Task(
description="Write an article based on research",
agent=writer,
expected_output="Article draft"
)
# Run workflow
agents = PraisonAIAgents(agents=[researcher, writer], tasks=[research_task, write_task])
result = agents.start()
```
---
## Agent Types
### 1. Agent (Base)
The core agent class with self-reflection, tool use, and streaming support.
```python
from praisonaiagents import Agent
agent = Agent(
name="Assistant",
instructions="You are helpful.",
model="gpt-4o-mini",
verbose=True,
self_reflect=True, # Enable self-reflection
max_reflect=3 # Max reflection iterations
)
```
### 2. DeepResearchAgent 🆕
Automated research agent using OpenAI or Gemini Deep Research APIs with real-time streaming.
```python
from praisonaiagents import DeepResearchAgent
# OpenAI Deep Research
agent = DeepResearchAgent(
model="o4-mini-deep-research", # or "o3-deep-research"
verbose=True
)
result = agent.research("What are the latest AI trends?")
print(result.report)
print(f"Citations: {len(result.citations)}")
# Gemini Deep Research
agent = DeepResearchAgent(
model="deep-research-pro", # Auto-detected as Gemini
verbose=True
)
result = agent.research("Research quantum computing advances")
```
**Features:**
- **Multi-provider**: OpenAI, Gemini, and LiteLLM support
- **Auto-detection**: Provider detected from model name
- **Streaming**: Real-time progress with reasoning summaries (default: enabled)
- **Citations**: Structured citations with URLs
- **Tools**: Web search, code interpreter, MCP, file search
### 3. QueryRewriterAgent 🆕
Transform user queries to improve RAG retrieval quality using multiple strategies.
```python
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent(model="gpt-4o-mini", verbose=True)
# Basic rewriting - expands abbreviations, adds context
result = agent.rewrite("AI trends")
print(result.primary_query)
# Output: "What are the current trends in Artificial Intelligence (AI)?"
# HyDE - generates hypothetical document for semantic matching
result = agent.rewrite("What is quantum computing?", strategy=RewriteStrategy.HYDE)
print(result.hypothetical_document)
# Step-back - generates broader context question
result = agent.rewrite("Difference between GPT-4 and Claude 3?", strategy=RewriteStrategy.STEP_BACK)
print(result.step_back_question)
# Sub-queries - decomposes complex questions
result = agent.rewrite("How to set up RAG and what embedding models to use?", strategy=RewriteStrategy.SUB_QUERIES)
print(result.sub_queries)
# Contextual - uses chat history to resolve references
result = agent.rewrite("What about its cost?", strategy=RewriteStrategy.CONTEXTUAL, chat_history=[...])
```
**Strategies:**
- **BASIC**: Expand abbreviations, fix typos, add context
- **HYDE**: Generate hypothetical document for better semantic matching
- **STEP_BACK**: Generate higher-level concept questions
- **SUB_QUERIES**: Decompose multi-part questions
- **MULTI_QUERY**: Generate multiple paraphrased versions
- **CONTEXTUAL**: Resolve references using conversation history
- **AUTO**: Automatically detect best strategy
### 4. ImageAgent
Agent specialized for image generation and analysis.
```python
from praisonaiagents import ImageAgent
agent = ImageAgent(
name="Artist",
instructions="Generate creative images"
)
result = agent.chat("Create an image of a sunset over mountains")
```
### 5. ContextAgent
Agent with persistent context across conversations.
```python
from praisonaiagents import ContextAgent
agent = ContextAgent(
name="Context Agent",
instructions="Remember our conversation"
)
```
### 6. RouterAgent
Routes requests to appropriate specialized agents.
```python
from praisonaiagents.agent import RouterAgent
router = RouterAgent(
agents=[weather_agent, math_agent, general_agent],
instructions="Route to the best agent for each query"
)
```
---
## Memory
Persistent memory with short-term, long-term, and graph memory support.
```python
from praisonaiagents import Agent, Memory
memory = Memory(
provider="chroma", # or "mongodb", "rag"
use_short_term=True,
use_long_term=True
)
agent = Agent(
name="Memory Agent",
memory=memory
)
```
**Memory Types:**
- **Short-term**: Recent conversation context
- **Long-term**: Persistent storage across sessions
- **Graph**: Relationship-based memory with Mem0
---
## Knowledge Base
Add documents and data sources to your agents.
```python
from praisonaiagents import Agent, Knowledge
knowledge = Knowledge(
sources=["docs/", "data.pdf", "https://example.com"],
chunking_method="semantic"
)
agent = Agent(
name="Knowledge Agent",
knowledge=knowledge
)
```
**Supported Sources:**
- PDF, Word, Excel, CSV files
- Directories of documents
- URLs and web pages
- Databases
---
## Tools
### Built-in Tools
```python
from praisonaiagents.tools import (
# Search
duckduckgo_search,
searxng_search,
# Data
read_csv, write_csv,
read_json, write_json,
read_yaml, write_yaml,
read_excel, write_excel,
# Finance
get_stock_price, get_stock_info,
# Research
arxiv_search,
wikipedia_search,
# Web
spider_scrape,
newspaper_extract,
# System
execute_shell,
run_python,
# Database
duckdb_query,
mongodb_query
)
```
### Custom Tools
```python
def my_tool(param: str) -> str:
"""Tool description for the agent."""
return f"Result: {param}"
agent = Agent(tools=[my_tool])
```
---
## MCP (Model Context Protocol)
Connect to MCP servers for extended capabilities.
```python
from praisonaiagents import Agent, MCP
# Local MCP server
agent = Agent(
tools=MCP(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/path"]
)
)
# Remote MCP server (SSE)
agent = Agent(
tools=MCP(url="http://localhost:8080/sse")
)
# With environment variables
agent = Agent(
tools=MCP(
command="npx",
args=["-y", "@modelcontextprotocol/server-brave-search"],
env={"BRAVE_API_KEY": "your-key"}
)
)
```
---
## Guardrails
Add safety checks and validation to agent responses.
```python
from praisonaiagents import Agent, LLMGuardrail
# LLM-based guardrail
guardrail = LLMGuardrail(
instructions="Ensure responses are professional and accurate"
)
agent = Agent(
name="Safe Agent",
guardrail=guardrail
)
```
---
## Handoffs
Transfer conversations between agents.
```python
from praisonaiagents import Agent, handoff
support_agent = Agent(name="Support", instructions="Handle support queries")
sales_agent = Agent(name="Sales", instructions="Handle sales queries")
# Enable handoffs
support_agent.handoffs = [handoff(sales_agent, "Transfer to sales")]
```
---
## Streaming
Real-time streaming responses.
```python
from praisonaiagents import Agent
agent = Agent(name="Streamer", verbose=True)
# Streaming is automatic with verbose=True
response = agent.chat("Tell me a story")
# Or use the stream method
for chunk in agent.stream("Tell me a story"):
print(chunk, end="", flush=True)
```
---
## Async Support
Full async/await support for all operations.
```python
import asyncio
from praisonaiagents import Agent
agent = Agent(name="Async Agent")
async def main():
response = await agent.achat("Hello!")
print(response)
asyncio.run(main())
```
---
## Telemetry
Built-in telemetry for monitoring and analytics.
```python
from praisonaiagents import enable_telemetry, disable_telemetry
# Enable full telemetry
enable_telemetry()
# Disable telemetry
disable_telemetry()
```
**Environment Variables:**
- `PRAISONAI_DISABLE_TELEMETRY=true` - Disable all telemetry
- `PRAISONAI_PERFORMANCE_MODE=true` - Minimal overhead mode
- `DO_NOT_TRACK=true` - Respect DNT preference
---
## Supported LLM Providers
PraisonAI Agents works with any LLM provider via LiteLLM:
| Provider | Model Example |
|----------|---------------|
| OpenAI | `gpt-4o`, `gpt-4o-mini`, `o1`, `o3` |
| Anthropic | `claude-3-5-sonnet`, `claude-3-opus` |
| Google | `gemini-2.0-flash`, `gemini-pro` |
| Ollama | `ollama/llama3`, `ollama/mistral` |
| Azure | `azure/gpt-4` |
| AWS Bedrock | `bedrock/claude-3` |
| Groq | `groq/llama3-70b` |
| Together | `together/mixtral-8x7b` |
```python
# Use any provider
agent = Agent(model="anthropic/claude-3-5-sonnet")
agent = Agent(model="ollama/llama3")
agent = Agent(model="gemini/gemini-2.0-flash")
```
---
## Configuration
### Environment Variables
```bash
python server.py
# API Keys
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GEMINI_API_KEY=...
GOOGLE_API_KEY=...
# Logging
LOGLEVEL=DEBUG # DEBUG, INFO, WARNING, ERROR
# Telemetry
PRAISONAI_DISABLE_TELEMETRY=true
```
By default, the server runs on 0.0.0.0:8080, but you can customize the host and port:
---
```bash
python server.py --host 127.0.0.1 --port 8081
## Examples
### Research Agent with Citations
```python
from praisonaiagents import DeepResearchAgent
agent = DeepResearchAgent(
model="o4-mini-deep-research",
instructions="Provide data-rich insights with citations",
verbose=True
)
result = agent.research("Economic impact of AI on healthcare")
print(result.report)
for citation in result.citations:
print(f"- {citation.title}: {citation.url}")
```
### Running the Standalone Client
### Multi-Agent Research Team
The standalone client uses Claude to interact with the MCP server tools:
```python
from praisonaiagents import Agent, Task, PraisonAIAgents
```bash
# Set your Anthropic API key
export ANTHROPIC_API_KEY=your_api_key_here
researcher = Agent(
name="Researcher",
instructions="Research topics thoroughly",
tools=[duckduckgo_search]
)
# Run the client
python client.py http://0.0.0.0:8080/sse
analyst = Agent(
name="Analyst",
instructions="Analyze data and provide insights"
)
writer = Agent(
name="Writer",
instructions="Write clear reports"
)
tasks = [
Task(description="Research AI trends", agent=researcher),
Task(description="Analyze findings", agent=analyst),
Task(description="Write report", agent=writer)
]
team = PraisonAIAgents(agents=[researcher, analyst, writer], tasks=tasks)
result = team.start()
```
You'll see a prompt where you can type queries for Claude to process using the MCP tools.
### Agent with Memory and Knowledge
### Running the praisonaiagents Client
```python
from praisonaiagents import Agent, Memory, Knowledge
The praisonaiagents client uses OpenAI to interact with the MCP server tools:
```bash
# Set your OpenAI API key
export OPENAI_API_KEY=your_api_key_here
# Run the client
python mcp-sse.py
agent = Agent(
name="Smart Assistant",
memory=Memory(use_long_term=True),
knowledge=Knowledge(sources=["docs/"]),
instructions="Help users with their questions using available knowledge"
)
```
This will automatically send a query about the weather in Paris to the agent.
---
## How It Works
## API Reference
1. The server exposes MCP tools via an SSE endpoint
2. Clients connect to this endpoint and discover available tools
3. When a user makes a query, the client:
- For client.py: Uses Claude to determine which tool to call
- For mcp-sse.py: Uses OpenAI to determine which tool to call
4. The client executes the tool call against the server
5. The result is returned to the user
### Agent
This pattern allows for decoupled processes where the MCP server can run independently of clients, making it suitable for cloud-native applications.
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `name` | str | "Agent" | Agent name |
| `instructions` | str | "" | System instructions |
| `model` | str | "gpt-4o-mini" | LLM model |
| `tools` | list | [] | Available tools |
| `memory` | Memory | None | Memory instance |
| `knowledge` | Knowledge | None | Knowledge base |
| `verbose` | bool | False | Enable verbose output |
| `self_reflect` | bool | False | Enable self-reflection |
| `max_reflect` | int | 3 | Max reflection iterations |
## Customizing
### DeepResearchAgent
- To add more tools to the server, define new functions with the `@mcp.tool()` decorator in `server.py`
- To change the client's behavior, update the instructions and query in `mcp-sse.py`
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `model` | str | "o3-deep-research" | Research model |
| `provider` | str | None | Force provider (openai/gemini/litellm) |
| `verbose` | bool | True | Show progress |
| `poll_interval` | int | 5 | Gemini poll interval (seconds) |
| `max_wait_time` | int | 3600 | Max research time (seconds) |
### Task
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `description` | str | required | Task description |
| `agent` | Agent | required | Assigned agent |
| `expected_output` | str | "" | Expected output format |
| `context` | list | [] | Context from other tasks |
---
## License
MIT License - see LICENSE file for details.
## Links
- [Documentation](https://docs.praison.ai)
- [GitHub](https://github.com/MervinPraison/PraisonAI)
- [PyPI](https://pypi.org/project/praisonaiagents/)
@@ -0,0 +1,48 @@
"""
Gemini Deep Research Agent Example
Uses Google's deep-research-pro model via the Interactions API
for automated research with web search.
Supports two modes:
1. Polling (default): Checks status periodically, shows progress logs
2. Streaming: Real-time output with thinking summaries (recommended)
Requirements:
- GEMINI_API_KEY or GOOGLE_API_KEY environment variable
- google-genai >= 1.55.0 (pip install google-genai)
"""
from dotenv import load_dotenv
load_dotenv()
from praisonaiagents import DeepResearchAgent
agent = DeepResearchAgent(
name="Gemini Researcher",
instructions="""
You are a professional researcher. Focus on:
- Comprehensive analysis with multiple perspectives
- Data-backed insights and trends
- Clear structure with executive summary
""",
model="deep-research-pro", # Auto-detected as Gemini
verbose=True,
)
print(f"Agent: {agent}")
print(f"Provider: {agent.provider}")
# Streaming is enabled by default for real-time progress updates
# This shows thinking summaries and streams the report as it's generated
result = agent.research(
"What is the current price of Ethereum?"
# stream=True is the default, set stream=False to disable
)
# The report is already printed during streaming when verbose=True
# But we can also access it programmatically:
print("\n" + "=" * 60)
print(f"Report length: {len(result.report)} characters")
print(f"Interaction ID: {result.interaction_id}")
print(f"Reasoning steps captured: {len(result.reasoning_steps)}")
print("=" * 60)
@@ -0,0 +1,47 @@
"""
OpenAI Deep Research Agent Example
Uses OpenAI's o3-deep-research or o4-mini-deep-research models
via the Responses API for automated research with web search.
Supports two modes:
1. Non-streaming (default): Waits for completion, returns full report
2. Streaming: Real-time progress with reasoning summaries and web searches
Requirements:
- OPENAI_API_KEY environment variable
"""
from dotenv import load_dotenv
load_dotenv()
from praisonaiagents import DeepResearchAgent
agent = DeepResearchAgent(
name="Research Assistant",
instructions="""
You are a professional researcher. Focus on:
- Data-rich insights with specific figures
- Reliable sources and citations
- Clear, structured responses
""",
model="o4-mini-deep-research", # or "o3-deep-research" for higher quality
verbose=True
)
print(f"Agent: {agent}")
print(f"Provider: {agent.provider}")
# Streaming is enabled by default for real-time progress updates
# Shows: reasoning summaries, web search queries, and report text as generated
result = agent.research(
"What is the current price of Bitcoin?"
# stream=True is the default, set stream=False to disable
)
# The report is already printed during streaming when verbose=True
# But we can also access it programmatically:
print("\n" + "=" * 60)
print(f"Report length: {len(result.report)} characters")
print(f"Citations: {len(result.citations)}")
print(f"Web searches: {len(result.web_searches)}")
print("=" * 60)
+8
View File
@@ -0,0 +1,8 @@
from praisonaiagents import Agent
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano"
)
agent.start("Why sky is Blue?")
agent.start("What was my previous question?")
+14
View File
@@ -0,0 +1,14 @@
from praisonaiagents import Agent
import asyncio
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano"
)
agent.run("Why sea is Blue?")
async def main():
await agent.arun("Why sky is Blue?")
await agent.arun("What was my previous question?")
asyncio.run(main())
@@ -15,6 +15,22 @@ _logging.configure_root_logger()
from .agent.agent import Agent
from .agent.image_agent import ImageAgent
from .agent.context_agent import ContextAgent, create_context_agent
from .agent.deep_research_agent import (
DeepResearchAgent,
DeepResearchResponse,
Citation,
ReasoningStep,
WebSearchCall,
CodeExecutionStep,
MCPCall,
FileSearchCall,
Provider
)
from .agent.query_rewriter_agent import (
QueryRewriterAgent,
RewriteStrategy,
RewriteResult
)
from .agents.agents import PraisonAIAgents
from .task.task import Task
from .tools.tools import Tools
@@ -186,7 +202,19 @@ __all__ = [
'disable_performance_mode',
'cleanup_telemetry_resources',
'MinimalTelemetry',
'TelemetryCollector'
'TelemetryCollector',
'DeepResearchAgent',
'DeepResearchResponse',
'Citation',
'ReasoningStep',
'WebSearchCall',
'CodeExecutionStep',
'MCPCall',
'FileSearchCall',
'Provider',
'QueryRewriterAgent',
'RewriteStrategy',
'RewriteResult'
]
# Add MCP to __all__ if available
@@ -4,5 +4,44 @@ from .image_agent import ImageAgent
from .context_agent import ContextAgent, create_context_agent
from .handoff import Handoff, handoff, handoff_filters, RECOMMENDED_PROMPT_PREFIX, prompt_with_handoff_instructions
from .router_agent import RouterAgent
from .deep_research_agent import (
DeepResearchAgent,
DeepResearchResponse,
Citation,
ReasoningStep,
WebSearchCall,
CodeExecutionStep,
MCPCall,
FileSearchCall,
Provider
)
from .query_rewriter_agent import (
QueryRewriterAgent,
RewriteStrategy,
RewriteResult
)
__all__ = ['Agent', 'ImageAgent', 'ContextAgent', 'create_context_agent', 'Handoff', 'handoff', 'handoff_filters', 'RECOMMENDED_PROMPT_PREFIX', 'prompt_with_handoff_instructions', 'RouterAgent']
__all__ = [
'Agent',
'ImageAgent',
'ContextAgent',
'create_context_agent',
'Handoff',
'handoff',
'handoff_filters',
'RECOMMENDED_PROMPT_PREFIX',
'prompt_with_handoff_instructions',
'RouterAgent',
'DeepResearchAgent',
'DeepResearchResponse',
'Citation',
'ReasoningStep',
'WebSearchCall',
'CodeExecutionStep',
'MCPCall',
'FileSearchCall',
'Provider',
'QueryRewriterAgent',
'RewriteStrategy',
'RewriteResult'
]
@@ -2082,13 +2082,17 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
display_error(f"Error in _achat_completion: {e}")
return None
async def arun(self, prompt: str, **kwargs):
"""Async alias for astart() method"""
return await self.astart(prompt, **kwargs)
async def astart(self, prompt: str, **kwargs):
"""Async version of start method"""
return await self.achat(prompt, **kwargs)
def run(self):
def run(self, prompt: str, **kwargs):
"""Alias for start() method"""
return self.start()
return self.start(prompt, **kwargs)
def start(self, prompt: str, **kwargs):
"""Start the agent with a prompt. This is a convenience method that wraps chat()."""
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,627 @@
"""
Query Rewriter Agent Module
This module provides the QueryRewriterAgent class for transforming user queries
to improve retrieval quality in RAG applications.
Supported Rewriting Strategies:
- **BASIC**: Simple rephrasing for clarity and keyword optimization
- **HYDE**: Hypothetical Document Embeddings - generates a hypothetical answer
- **STEP_BACK**: Generates higher-level concept questions for complex queries
- **SUB_QUERIES**: Decomposes multi-part questions into focused sub-queries
- **MULTI_QUERY**: Generates multiple paraphrased versions for ensemble retrieval
- **CONTEXTUAL**: Uses conversation history to resolve references and context
Example:
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent(verbose=True)
# Basic rewriting
result = agent.rewrite("AI trends")
print(result.rewritten_queries)
# HyDE for better semantic matching
result = agent.rewrite("What is quantum computing?", strategy=RewriteStrategy.HYDE)
print(result.hypothetical_document)
# Contextual with chat history
chat_history = [
{"role": "user", "content": "Tell me about Python"},
{"role": "assistant", "content": "Python is a programming language..."}
]
result = agent.rewrite("What about its performance?", chat_history=chat_history)
# With search tools for context-aware rewriting
from praisonaiagents.tools import internet_search
agent = QueryRewriterAgent(tools=[internet_search], verbose=True)
result = agent.rewrite("latest AI developments") # Searches first, then rewrites
"""
import logging
import json
from typing import List, Optional, Any, Dict
from dataclasses import dataclass, field
from enum import Enum
class RewriteStrategy(Enum):
"""Enumeration of available query rewriting strategies."""
BASIC = "basic"
HYDE = "hyde"
STEP_BACK = "step_back"
SUB_QUERIES = "sub_queries"
MULTI_QUERY = "multi_query"
CONTEXTUAL = "contextual"
AUTO = "auto"
@dataclass
class RewriteResult:
"""Result of a query rewriting operation."""
original_query: str
rewritten_queries: List[str]
strategy_used: RewriteStrategy
hypothetical_document: Optional[str] = None
step_back_question: Optional[str] = None
sub_queries: Optional[List[str]] = None
metadata: Dict[str, Any] = field(default_factory=dict)
def __repr__(self):
return f"RewriteResult(strategy={self.strategy_used.value}, queries={len(self.rewritten_queries)})"
@property
def primary_query(self) -> str:
"""Returns the primary rewritten query."""
return self.rewritten_queries[0] if self.rewritten_queries else self.original_query
@property
def all_queries(self) -> List[str]:
"""Returns all queries including original and rewritten."""
queries = [self.original_query]
queries.extend(self.rewritten_queries)
if self.step_back_question:
queries.append(self.step_back_question)
if self.sub_queries:
queries.extend(self.sub_queries)
return list(set(queries)) # Remove duplicates
class QueryRewriterAgent:
"""
Agent for rewriting queries to improve retrieval quality in RAG applications.
This agent transforms user queries using various strategies to bridge the gap
between how users ask questions and how information is stored in knowledge bases.
Attributes:
name: Name of the agent
model: LLM model to use for rewriting
verbose: Whether to print detailed logs
max_queries: Maximum number of queries to generate for multi-query strategy
abbreviations: Dictionary of common abbreviations to expand
Example:
agent = QueryRewriterAgent(model="gpt-4o-mini", verbose=True)
result = agent.rewrite("ML best practices", strategy=RewriteStrategy.MULTI_QUERY)
for query in result.rewritten_queries:
print(query)
"""
# Default prompts for each strategy
PROMPTS = {
"basic": """You are an expert at rewriting search queries for better retrieval.
Given the following query, rewrite it to be clearer, more specific, and better suited for searching a knowledge base.
Guidelines:
- Expand abbreviations and acronyms
- Fix typos and grammatical errors
- Add relevant context if the query is too short
- Transform keyword searches into natural questions
- Keep the original intent intact
Query: {query}
Rewritten query:""",
"hyde": """You are an expert at generating hypothetical documents.
Given the following query, write a detailed hypothetical document that would perfectly answer this query. This document will be used to find similar real documents in a knowledge base.
Guidelines:
- Write as if you are answering the query directly
- Include specific details, facts, and terminology
- Use the same style and vocabulary as the target documents
- Be comprehensive but focused on the query topic
Query: {query}
Hypothetical document:""",
"step_back": """You are an expert at generating step-back questions.
Given the following query, generate a more general, higher-level question that captures the broader concept. This helps retrieve background information needed to answer the specific query.
Guidelines:
- Identify the underlying concept or principle
- Create a question about fundamentals or general knowledge
- The step-back question should provide context for the original query
Query: {query}
Step-back question:""",
"sub_queries": """You are an expert at decomposing complex queries.
Given the following query, break it down into simpler, focused sub-queries. Each sub-query should address one specific aspect of the original question.
Guidelines:
- Identify distinct aspects or components of the query
- Create independent, self-contained sub-queries
- Each sub-query should be answerable on its own
- Return as a JSON array of strings
Query: {query}
Sub-queries (JSON array):""",
"multi_query": """You are an expert at query expansion and paraphrasing.
Given the following query, generate {num_queries} different versions that capture the same intent but use different words, phrases, or perspectives.
Guidelines:
- Use synonyms and alternative phrasings
- Try different question formats (what, how, why, etc.)
- Include both formal and informal versions
- Add relevant context or specificity
- Return as a JSON array of strings
Query: {query}
Alternative queries (JSON array):""",
"contextual": """You are an expert at understanding conversational context.
Given the conversation history and a follow-up query, rewrite the query as a standalone question that captures all relevant context.
Guidelines:
- Resolve pronouns and references (it, this, that, etc.)
- Include relevant context from the conversation
- Keep entity names and important details
- Make the query self-contained and clear
Conversation history:
{chat_history}
Follow-up query: {query}
Standalone question:""",
"auto": """You are an expert at analyzing and rewriting queries.
Analyze the following query and determine the best rewriting strategy, then apply it.
Query types to consider:
1. Short/keyword queries → Expand into full questions
2. Ambiguous queries → Clarify with context
3. Complex multi-part queries → Break into sub-queries
4. Follow-up queries → Resolve references from context
5. Well-formed queries → Minor optimization only
Query: {query}
{context}
Analysis and rewritten query:"""
}
def __init__(
self,
name: str = "QueryRewriterAgent",
model: str = "gpt-4o-mini",
instructions: Optional[str] = None,
verbose: bool = False,
max_queries: int = 5,
abbreviations: Optional[Dict[str, str]] = None,
temperature: float = 0.3,
max_tokens: int = 500,
tools: Optional[List[Any]] = None
):
"""
Initialize the QueryRewriterAgent.
Args:
name: Name of the agent
model: LLM model to use (default: gpt-4o-mini)
instructions: Custom instructions for the agent
verbose: Whether to print detailed logs
max_queries: Maximum queries for multi-query strategy
abbreviations: Custom abbreviation expansions
temperature: Temperature for LLM generation
max_tokens: Maximum tokens for LLM response
tools: Optional list of tools (agent decides when to use them)
"""
self.name = name
self.model = model
self.instructions = instructions
self.verbose = verbose
self.max_queries = max_queries
self.temperature = temperature
self.max_tokens = max_tokens
self.tools = tools or []
self._agent = None # Lazy initialized
# Default abbreviations (can be extended)
self.abbreviations = abbreviations or {
"AI": "Artificial Intelligence",
"ML": "Machine Learning",
"NLP": "Natural Language Processing",
"LLM": "Large Language Model",
"RAG": "Retrieval Augmented Generation",
"API": "Application Programming Interface",
"DB": "Database",
"UI": "User Interface",
"UX": "User Experience",
"SDK": "Software Development Kit",
"CLI": "Command Line Interface",
}
# Setup logging
self.logger = logging.getLogger(__name__)
if self.verbose:
self.logger.setLevel(logging.DEBUG)
@property
def agent(self):
"""Lazy initialization of internal Agent."""
if self._agent is None:
from .agent import Agent
self._agent = Agent(
name=self.name,
role="Query Rewriting Specialist",
goal="Rewrite queries for better search and retrieval results. Use available tools when needed to gather context.",
backstory="You are an expert at understanding user intent and transforming queries for optimal information retrieval.",
tools=self.tools,
llm=self.model,
verbose=self.verbose,
markdown=False
)
return self._agent
def _call_agent(self, prompt: str) -> str:
"""Call the internal Agent with the given prompt."""
try:
response = self.agent.chat(prompt)
return response if response else ""
except Exception as e:
self.logger.error(f"Agent call failed: {e}")
raise
def _expand_abbreviations(self, query: str) -> str:
"""Expand known abbreviations in the query."""
words = query.split()
expanded = []
for word in words:
clean_word = word.strip(".,!?;:")
if clean_word.upper() in self.abbreviations:
expanded.append(f"{clean_word} ({self.abbreviations[clean_word.upper()]})")
else:
expanded.append(word)
return " ".join(expanded)
def _is_short_query(self, query: str, threshold: int = 5) -> bool:
"""Check if query is considered short (keyword-style)."""
return len(query.split()) < threshold
def _parse_json_array(self, text: str) -> List[str]:
"""Parse a JSON array from LLM response."""
try:
# Try direct JSON parsing
result = json.loads(text)
if isinstance(result, list):
return [str(item) for item in result]
except json.JSONDecodeError:
pass
# Try to extract JSON array from text
import re
match = re.search(r'\[.*?\]', text, re.DOTALL)
if match:
try:
result = json.loads(match.group())
if isinstance(result, list):
return [str(item) for item in result]
except json.JSONDecodeError:
pass
# Fallback: split by newlines and clean up
lines = [line.strip() for line in text.split('\n') if line.strip()]
lines = [line.lstrip('0123456789.-) ').strip('"\'') for line in lines]
return [line for line in lines if line and len(line) > 3]
def rewrite(
self,
query: str,
strategy: RewriteStrategy = RewriteStrategy.AUTO,
chat_history: Optional[List[Dict[str, str]]] = None,
context: Optional[str] = None,
num_queries: int = None
) -> RewriteResult:
"""
Rewrite a query using the specified strategy.
All operations go through an internal Agent which automatically handles
tool calling when tools are provided. The agent decides when to use tools
based on the query context.
Args:
query: The original user query
strategy: Rewriting strategy to use
chat_history: Previous conversation messages for contextual rewriting
context: Additional context about the knowledge base
num_queries: Number of queries for multi-query strategy
Returns:
RewriteResult containing rewritten queries
"""
if self.verbose:
self.logger.debug(f"Rewriting query: '{query}' with strategy: {strategy.value}")
if self.tools:
print(f"[cyan]Agent has {len(self.tools)} tools available (will use if needed)...[/cyan]")
# Auto-detect strategy if needed
if strategy == RewriteStrategy.AUTO:
strategy = self._detect_strategy(query, chat_history)
if self.verbose:
self.logger.debug(f"Auto-detected strategy: {strategy.value}")
# All calls go through the internal Agent which handles tool calling
combined_context = context or ""
# Dispatch to appropriate method
if strategy == RewriteStrategy.BASIC:
return self._rewrite_basic(query, combined_context)
elif strategy == RewriteStrategy.HYDE:
return self._rewrite_hyde(query, combined_context)
elif strategy == RewriteStrategy.STEP_BACK:
return self._rewrite_step_back(query, combined_context)
elif strategy == RewriteStrategy.SUB_QUERIES:
return self._rewrite_sub_queries(query, combined_context)
elif strategy == RewriteStrategy.MULTI_QUERY:
return self._rewrite_multi_query(query, num_queries or self.max_queries, combined_context)
elif strategy == RewriteStrategy.CONTEXTUAL:
return self._rewrite_contextual(query, chat_history or [], combined_context)
else:
# Default to basic
return self._rewrite_basic(query, combined_context)
def _detect_strategy(
self,
query: str,
chat_history: Optional[List[Dict[str, str]]] = None
) -> RewriteStrategy:
"""Auto-detect the best rewriting strategy for a query."""
# If chat history exists and query seems like a follow-up
if chat_history and self._is_follow_up(query):
return RewriteStrategy.CONTEXTUAL
# Short keyword queries
if self._is_short_query(query):
return RewriteStrategy.BASIC
# Complex multi-part queries
if self._is_complex_query(query):
return RewriteStrategy.SUB_QUERIES
# Questions that might benefit from step-back
if self._needs_step_back(query):
return RewriteStrategy.STEP_BACK
# Default to basic
return RewriteStrategy.BASIC
def _is_follow_up(self, query: str) -> bool:
"""Check if query appears to be a follow-up question."""
follow_up_indicators = [
"it", "this", "that", "they", "them", "their",
"what about", "how about", "and", "also", "more",
"same", "similar", "related"
]
query_lower = query.lower()
return any(indicator in query_lower for indicator in follow_up_indicators)
def _is_complex_query(self, query: str) -> bool:
"""Check if query contains multiple distinct questions."""
# Check for multiple question marks or conjunctions
if query.count('?') > 1:
return True
complex_indicators = [" and ", " or ", " also ", " as well as ", " plus "]
return any(ind in query.lower() for ind in complex_indicators)
def _needs_step_back(self, query: str) -> bool:
"""Check if query would benefit from a step-back question."""
# Queries about specific details often benefit from broader context
specific_indicators = [
"specific", "exactly", "precisely", "particular",
"difference between", "compare", "versus", "vs"
]
return any(ind in query.lower() for ind in specific_indicators)
def _rewrite_basic(self, query: str, context: str = "") -> RewriteResult:
"""Basic query rewriting for clarity and keyword optimization."""
# First expand abbreviations
expanded_query = self._expand_abbreviations(query)
# Build prompt with optional context
prompt = self.PROMPTS["basic"].format(query=expanded_query)
if context:
prompt += f"\n\nAdditional context to help with rewriting:\n{context}"
rewritten = self._call_agent(prompt).strip()
return RewriteResult(
original_query=query,
rewritten_queries=[rewritten],
strategy_used=RewriteStrategy.BASIC,
metadata={"expanded_abbreviations": expanded_query != query, "has_context": bool(context)}
)
def _rewrite_hyde(self, query: str, context: str = "") -> RewriteResult:
"""HyDE: Generate hypothetical document for better semantic matching."""
prompt = self.PROMPTS["hyde"].format(query=query)
if context:
prompt += f"\n\nUse this context to make the hypothetical document more accurate:\n{context}"
hypothetical_doc = self._call_agent(prompt).strip()
# The hypothetical document itself becomes the search query
return RewriteResult(
original_query=query,
rewritten_queries=[hypothetical_doc[:500]], # Truncate for embedding
strategy_used=RewriteStrategy.HYDE,
hypothetical_document=hypothetical_doc,
metadata={"full_document_length": len(hypothetical_doc), "has_context": bool(context)}
)
def _rewrite_step_back(self, query: str, context: str = "") -> RewriteResult:
"""Generate step-back question for broader context retrieval."""
# Generate step-back question
prompt = self.PROMPTS["step_back"].format(query=query)
if context:
prompt += f"\n\nContext:\n{context}"
step_back = self._call_agent(prompt).strip()
# Also do basic rewriting of original
basic_result = self._rewrite_basic(query, context)
return RewriteResult(
original_query=query,
rewritten_queries=basic_result.rewritten_queries,
strategy_used=RewriteStrategy.STEP_BACK,
step_back_question=step_back,
metadata={"includes_step_back": True, "has_context": bool(context)}
)
def _rewrite_sub_queries(self, query: str, context: str = "") -> RewriteResult:
"""Decompose complex query into focused sub-queries."""
prompt = self.PROMPTS["sub_queries"].format(query=query)
if context:
prompt += f"\n\nContext to help with decomposition:\n{context}"
response = self._call_agent(prompt).strip()
sub_queries = self._parse_json_array(response)
# Ensure we have at least one sub-query
if not sub_queries:
sub_queries = [query]
return RewriteResult(
original_query=query,
rewritten_queries=sub_queries,
strategy_used=RewriteStrategy.SUB_QUERIES,
sub_queries=sub_queries,
metadata={"num_sub_queries": len(sub_queries), "has_context": bool(context)}
)
def _rewrite_multi_query(self, query: str, num_queries: int, context: str = "") -> RewriteResult:
"""Generate multiple paraphrased versions for ensemble retrieval."""
prompt = self.PROMPTS["multi_query"].format(
query=query,
num_queries=num_queries
)
if context:
prompt += f"\n\nContext to help with paraphrasing:\n{context}"
response = self._call_agent(prompt).strip()
queries = self._parse_json_array(response)
# Ensure we have queries and limit to max
if not queries:
queries = [query]
queries = queries[:num_queries]
return RewriteResult(
original_query=query,
rewritten_queries=queries,
strategy_used=RewriteStrategy.MULTI_QUERY,
metadata={"num_generated": len(queries), "has_context": bool(context)}
)
def _rewrite_contextual(
self,
query: str,
chat_history: List[Dict[str, str]],
context: str = ""
) -> RewriteResult:
"""Rewrite query using conversation context."""
# Format chat history
history_str = ""
for msg in chat_history[-10:]: # Last 10 messages
role = msg.get("role", "user")
content = msg.get("content", "")
history_str += f"{role.capitalize()}: {content}\n"
prompt = self.PROMPTS["contextual"].format(
chat_history=history_str,
query=query
)
if context:
prompt += f"\n\nAdditional context:\n{context}"
rewritten = self._call_agent(prompt).strip()
return RewriteResult(
original_query=query,
rewritten_queries=[rewritten],
strategy_used=RewriteStrategy.CONTEXTUAL,
metadata={
"history_length": len(chat_history),
"history_used": min(10, len(chat_history)),
"has_context": bool(context)
}
)
# Convenience methods for direct strategy access
def rewrite_basic(self, query: str) -> RewriteResult:
"""Convenience method for basic rewriting."""
return self.rewrite(query, strategy=RewriteStrategy.BASIC)
def rewrite_hyde(self, query: str) -> RewriteResult:
"""Convenience method for HyDE rewriting."""
return self.rewrite(query, strategy=RewriteStrategy.HYDE)
def rewrite_step_back(self, query: str) -> RewriteResult:
"""Convenience method for step-back rewriting."""
return self.rewrite(query, strategy=RewriteStrategy.STEP_BACK)
def rewrite_sub_queries(self, query: str) -> RewriteResult:
"""Convenience method for sub-query decomposition."""
return self.rewrite(query, strategy=RewriteStrategy.SUB_QUERIES)
def rewrite_multi_query(self, query: str, num_queries: int = None) -> RewriteResult:
"""Convenience method for multi-query generation."""
return self.rewrite(
query,
strategy=RewriteStrategy.MULTI_QUERY,
num_queries=num_queries
)
def rewrite_contextual(
self,
query: str,
chat_history: List[Dict[str, str]]
) -> RewriteResult:
"""Convenience method for contextual rewriting."""
return self.rewrite(
query,
strategy=RewriteStrategy.CONTEXTUAL,
chat_history=chat_history
)
def add_abbreviation(self, abbrev: str, expansion: str) -> None:
"""Add a custom abbreviation expansion."""
self.abbreviations[abbrev.upper()] = expansion
def add_abbreviations(self, abbreviations: Dict[str, str]) -> None:
"""Add multiple custom abbreviation expansions."""
for abbrev, expansion in abbreviations.items():
self.abbreviations[abbrev.upper()] = expansion
@@ -907,7 +907,7 @@ class LLM:
prompt: Union[str, List[Dict]],
system_prompt: Optional[str] = None,
chat_history: Optional[List[Dict]] = None,
temperature: float = 0.2,
temperature: float = 1.0,
tools: Optional[List[Any]] = None,
output_json: Optional[BaseModel] = None,
output_pydantic: Optional[BaseModel] = None,
@@ -2042,7 +2042,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
prompt: Union[str, List[Dict]],
system_prompt: Optional[str] = None,
chat_history: Optional[List[Dict]] = None,
temperature: float = 0.2,
temperature: float = 1.0,
tools: Optional[List[Any]] = None,
output_json: Optional[BaseModel] = None,
output_pydantic: Optional[BaseModel] = None,
@@ -2317,7 +2317,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
prompt: Union[str, List[Dict]],
system_prompt: Optional[str] = None,
chat_history: Optional[List[Dict]] = None,
temperature: float = 0.2,
temperature: float = 1.0,
tools: Optional[List[Any]] = None,
output_json: Optional[BaseModel] = None,
output_pydantic: Optional[BaseModel] = None,
@@ -3262,7 +3262,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
self,
prompt: Union[str, List[Dict]],
system_prompt: Optional[str] = None,
temperature: float = 0.2,
temperature: float = 1.0,
stream: bool = True,
verbose: bool = True,
markdown: bool = True,
@@ -3357,7 +3357,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
self,
prompt: Union[str, List[Dict]],
system_prompt: Optional[str] = None,
temperature: float = 0.2,
temperature: float = 1.0,
stream: bool = True,
verbose: bool = True,
markdown: bool = True,
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.0.160"
version = "0.0.168"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
requires-python = ">=3.10"
authors = [
@@ -0,0 +1,141 @@
"""
Query Rewriter Agent Example
Demonstrates various query rewriting strategies for improving RAG retrieval.
"""
from dotenv import load_dotenv
load_dotenv()
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
def main():
# Initialize the agent
agent = QueryRewriterAgent(
model="gpt-4o-mini",
verbose=True
)
print("=" * 60)
print("Query Rewriter Agent Examples")
print("=" * 60)
# 1. Basic Rewriting - Short keyword queries
print("\n1. BASIC REWRITING (Short Queries)")
print("-" * 40)
short_queries = [
"AI trends",
"python performance",
"RAG best practices"
]
for query in short_queries:
result = agent.rewrite(query, strategy=RewriteStrategy.BASIC)
print(f"Original: {query}")
print(f"Rewritten: {result.primary_query}")
print()
# 2. HyDE - Hypothetical Document Embeddings
print("\n2. HYDE (Hypothetical Document)")
print("-" * 40)
query = "What is quantum computing?"
result = agent.rewrite(query, strategy=RewriteStrategy.HYDE)
print(f"Original: {query}")
print("Hypothetical Document (truncated):")
print(f"{result.hypothetical_document[:300]}...")
print()
# 3. Step-Back - Higher-level concept questions
print("\n3. STEP-BACK (Broader Context)")
print("-" * 40)
query = "What is the difference between GPT-4 and Claude 3?"
result = agent.rewrite(query, strategy=RewriteStrategy.STEP_BACK)
print(f"Original: {query}")
print(f"Rewritten: {result.primary_query}")
print(f"Step-back Question: {result.step_back_question}")
print()
# 4. Sub-Queries - Decompose complex questions
print("\n4. SUB-QUERIES (Decomposition)")
print("-" * 40)
query = "How do I set up a RAG pipeline with vector search and what are the best embedding models to use?"
result = agent.rewrite(query, strategy=RewriteStrategy.SUB_QUERIES)
print(f"Original: {query}")
print("Sub-queries:")
for i, sq in enumerate(result.sub_queries, 1):
print(f" {i}. {sq}")
print()
# 5. Multi-Query - Multiple paraphrased versions
print("\n5. MULTI-QUERY (Ensemble Retrieval)")
print("-" * 40)
query = "How to improve LLM response quality?"
result = agent.rewrite(query, strategy=RewriteStrategy.MULTI_QUERY, num_queries=3)
print(f"Original: {query}")
print("Alternative queries:")
for i, q in enumerate(result.rewritten_queries, 1):
print(f" {i}. {q}")
print()
# 6. Contextual - Using conversation history
print("\n6. CONTEXTUAL (With Chat History)")
print("-" * 40)
chat_history = [
{"role": "user", "content": "Tell me about Python programming"},
{"role": "assistant", "content": "Python is a high-level programming language known for its simplicity and readability..."},
{"role": "user", "content": "What frameworks are popular?"},
{"role": "assistant", "content": "Popular Python frameworks include Django for web development, FastAPI for APIs, and PyTorch for ML..."}
]
query = "What about its performance compared to others?"
result = agent.rewrite(query, strategy=RewriteStrategy.CONTEXTUAL, chat_history=chat_history)
print(f"Original: {query}")
print(f"Standalone: {result.primary_query}")
print()
# 7. AUTO - Automatic strategy detection
print("\n7. AUTO (Automatic Strategy Detection)")
print("-" * 40)
test_queries = [
("ML", None), # Short query -> BASIC
("What about the cost?", chat_history), # Follow-up -> CONTEXTUAL
("Compare transformers vs RNNs and explain their use cases", None), # Complex -> SUB_QUERIES
]
for query, history in test_queries:
result = agent.rewrite(query, strategy=RewriteStrategy.AUTO, chat_history=history)
print(f"Query: {query}")
print(f"Detected Strategy: {result.strategy_used.value}")
print(f"Result: {result.primary_query}")
print()
# 8. Custom Abbreviations
print("\n8. CUSTOM ABBREVIATIONS")
print("-" * 40)
agent.add_abbreviations({
"K8s": "Kubernetes",
"TF": "TensorFlow",
"PT": "PyTorch"
})
query = "K8s deployment for TF models"
result = agent.rewrite(query, strategy=RewriteStrategy.BASIC)
print(f"Original: {query}")
print(f"Rewritten: {result.primary_query}")
print()
print("=" * 60)
print("Examples Complete!")
print("=" * 60)
if __name__ == "__main__":
main()
@@ -0,0 +1,344 @@
"""
Deep Research Agent Examples
This file demonstrates how to use the DeepResearchAgent for automated
complex research workflows using multiple providers:
- **OpenAI**: o3-deep-research, o4-mini-deep-research (via Responses API)
- **Gemini**: deep-research-pro (via Interactions API)
- **LiteLLM**: Unified interface for OpenAI models
Requirements:
- OPENAI_API_KEY for OpenAI/LiteLLM providers
- GEMINI_API_KEY for Gemini provider
- OpenAI SDK >= 1.0.0
- google-genai for Gemini (pip install google-genai)
- litellm for LiteLLM provider (pip install litellm)
Available models:
OpenAI:
- o3-deep-research: Higher quality, in-depth synthesis
- o4-mini-deep-research: Faster, lightweight
Gemini:
- deep-research-pro: Gemini 3 Pro powered research agent
"""
from praisonaiagents import DeepResearchAgent, Provider
# =============================================================================
# Example 1: Basic Research Query
# =============================================================================
def basic_research_example():
"""Simple research query with default settings."""
agent = DeepResearchAgent(
name="Research Assistant",
instructions="""
You are a professional researcher. Focus on:
- Data-rich insights with specific figures and trends
- Reliable sources: peer-reviewed research, official reports
- Include inline citations
""",
model="o4-mini-deep-research", # Use faster model
verbose=True
)
result = agent.research(
"What are the key trends in renewable energy adoption in 2024?"
)
print("=" * 60)
print("RESEARCH REPORT")
print("=" * 60)
print(result.report)
print("\n" + "=" * 60)
print("CITATIONS")
print("=" * 60)
for i, citation in enumerate(result.citations, 1):
print(f"{i}. {citation.title}")
print(f" URL: {citation.url}")
return result
# =============================================================================
# Example 2: Gemini Deep Research
# =============================================================================
def gemini_research_example():
"""Research using Gemini Deep Research Agent."""
agent = DeepResearchAgent(
name="Gemini Researcher",
instructions="""
You are a professional researcher. Focus on:
- Comprehensive analysis with multiple perspectives
- Data-backed insights and trends
- Clear structure with executive summary
""",
model="deep-research-pro", # Gemini model - auto-detected
verbose=True
)
print(f"Using provider: {agent.provider}") # Should be Provider.GEMINI
result = agent.research(
"What are the latest breakthroughs in fusion energy research?"
)
print("=" * 60)
print("GEMINI RESEARCH REPORT")
print("=" * 60)
print(result.report[:1000] + "..." if len(result.report) > 1000 else result.report)
return result
# =============================================================================
# Example 3: Research with Code Interpreter (OpenAI)
# =============================================================================
def research_with_code_example():
"""Research with code execution for data analysis."""
agent = DeepResearchAgent(
name="Data Analyst",
instructions="""
You are a data analyst. When appropriate:
- Use code to analyze data and create visualizations
- Summarize data in tables
- Include specific statistics and metrics
""",
model="o3-deep-research",
enable_code_interpreter=True,
verbose=True
)
result = agent.research(
"Analyze the global smartphone market share trends over the past 5 years.",
summary_mode="detailed"
)
# Check if any code was executed
if result.code_executions:
print("\nCode executed during research:")
for code in result.code_executions:
print(f" Input: {code.input_code[:100]}...")
if code.output:
print(f" Output: {code.output[:100]}...")
return result
# =============================================================================
# Example 4: Using LiteLLM Provider
# =============================================================================
def litellm_research_example():
"""Research using LiteLLM for unified interface."""
agent = DeepResearchAgent(
name="LiteLLM Researcher",
instructions="You are a professional researcher.",
model="o3-deep-research",
use_litellm=True, # Use LiteLLM instead of direct OpenAI
verbose=True
)
print(f"Using provider: {agent.provider}") # Should be Provider.LITELLM
result = agent.research(
"What are the key trends in sustainable agriculture?"
)
print(f"Report length: {len(result.report)} characters")
return result
# =============================================================================
# Example 5: Research with MCP Integration (OpenAI)
# =============================================================================
def research_with_mcp_example():
"""Research with custom MCP server for internal documents."""
agent = DeepResearchAgent(
name="Internal Researcher",
instructions="""
You are a researcher with access to internal documents.
- Use the internal file lookup tool to retrieve company data
- Combine internal data with public research
- Prioritize internal sources when available
""",
model="o3-deep-research",
mcp_servers=[
{
"label": "internal_docs",
"url": "https://your-mcp-server.com/sse/",
"require_approval": "never"
}
],
verbose=True
)
result = agent.research(
"What is our company's market position compared to competitors?"
)
# Check MCP calls
if result.mcp_calls:
print("\nMCP tools used:")
for call in result.mcp_calls:
print(f" - {call.name}@{call.server_label}: {call.arguments}")
return result
# =============================================================================
# Example 6: Gemini with File Search
# =============================================================================
def gemini_file_search_example():
"""Research using Gemini with your own data via File Search."""
agent = DeepResearchAgent(
name="Document Researcher",
instructions="""
Compare our internal documents against current public information.
Prioritize insights from our internal data.
""",
model="deep-research-pro",
enable_file_search=True,
file_search_stores=["fileSearchStores/my-store-name"],
verbose=True
)
result = agent.research(
"Compare our 2025 fiscal year report against current market trends."
)
return result
# =============================================================================
# Example 7: Clarifying Questions Workflow
# =============================================================================
def clarifying_workflow_example():
"""Use clarifying questions before research."""
agent = DeepResearchAgent(
name="Research Assistant",
verbose=True
)
# Step 1: Get clarifying questions
initial_query = "Help me research AI trends"
questions = agent.clarify(initial_query)
print("Clarifying Questions:")
print(questions)
# Step 2: User provides more details (simulated)
detailed_query = """
I'd like to research AI trends in healthcare specifically.
Focus on:
- Diagnostic AI applications
- FDA-approved AI tools
- Cost savings for hospitals
Time period: 2023-2024
"""
# Step 3: Rewrite the query for optimal research
rewritten = agent.rewrite_query(detailed_query)
print("\nRewritten Query:")
print(rewritten)
# Step 4: Perform the research
result = agent.research(rewritten)
return result
# =============================================================================
# Example 5: Async Research
# =============================================================================
async def async_research_example():
"""Perform research asynchronously."""
import asyncio
agent = DeepResearchAgent(
name="Async Researcher",
model="o4-mini-deep-research",
verbose=True
)
# Run multiple research queries concurrently
queries = [
"What are the latest developments in quantum computing?",
"What are the trends in electric vehicle adoption?",
]
tasks = [agent.aresearch(q) for q in queries]
results = await asyncio.gather(*tasks)
for query, result in zip(queries, results):
print(f"\nQuery: {query}")
print(f"Report length: {len(result.report)} chars")
print(f"Citations: {len(result.citations)}")
return results
# =============================================================================
# Example 6: Inspecting Intermediate Steps
# =============================================================================
def inspect_steps_example():
"""Inspect the research process steps."""
agent = DeepResearchAgent(
name="Detailed Researcher",
model="o4-mini-deep-research",
verbose=True
)
result = agent.research(
"What are the environmental impacts of cryptocurrency mining?"
)
print("\n" + "=" * 60)
print("RESEARCH PROCESS ANALYSIS")
print("=" * 60)
# Reasoning steps
print(f"\nReasoning Steps ({len(result.reasoning_steps)}):")
for i, step in enumerate(result.reasoning_steps, 1):
print(f" {i}. {step.text[:100]}...")
# Web searches
print(f"\nWeb Searches ({len(result.web_searches)}):")
for search in result.web_searches:
print(f" - Query: {search.query}")
print(f" Status: {search.status}")
# Sources
print(f"\nUnique Sources ({len(result.get_all_sources())}):")
for source in result.get_all_sources()[:10]:
print(f" - {source['title']}")
print(f" {source['url']}")
return result
# =============================================================================
# Main
# =============================================================================
if __name__ == "__main__":
import os
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
print("Please set it before running examples:")
print(" export OPENAI_API_KEY='your-api-key'")
exit(1)
print("Running basic research example...")
result = basic_research_example()
print(f"\nCompleted! Report has {len(result.report)} characters and {len(result.citations)} citations.")
@@ -0,0 +1,283 @@
"""
Test file for DeepResearchAgent
This file tests the OpenAI Deep Research API integration.
Requires OPENAI_API_KEY environment variable to be set.
Usage:
python tests/deep_research_test.py
"""
import os
import sys
# Add parent directory to path for imports
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from praisonaiagents import (
DeepResearchAgent,
DeepResearchResponse,
Citation,
ReasoningStep,
WebSearchCall,
CodeExecutionStep,
MCPCall,
FileSearchCall,
Provider
)
def test_basic_import():
"""Test that all classes can be imported."""
print("✓ All Deep Research classes imported successfully")
print(f" - DeepResearchAgent: {DeepResearchAgent}")
print(f" - DeepResearchResponse: {DeepResearchResponse}")
print(f" - Citation: {Citation}")
print(f" - ReasoningStep: {ReasoningStep}")
print(f" - WebSearchCall: {WebSearchCall}")
print(f" - CodeExecutionStep: {CodeExecutionStep}")
print(f" - MCPCall: {MCPCall}")
print(f" - FileSearchCall: {FileSearchCall}")
print(f" - Provider: {Provider}")
print(f" - Provider.OPENAI: {Provider.OPENAI}")
print(f" - Provider.GEMINI: {Provider.GEMINI}")
print(f" - Provider.LITELLM: {Provider.LITELLM}")
return True
def test_agent_initialization():
"""Test DeepResearchAgent initialization."""
# Check if API key is available
if not os.environ.get("OPENAI_API_KEY"):
print("⚠ Skipping initialization test - OPENAI_API_KEY not set")
return True
agent = DeepResearchAgent(
name="Test Researcher",
instructions="You are a professional researcher.",
model="o3-deep-research",
verbose=True
)
print(f"✓ Agent initialized: {agent}")
print(f" - Name: {agent.name}")
print(f" - Model: {agent.model}")
print(f" - Web search enabled: {agent.enable_web_search}")
print(f" - Code interpreter enabled: {agent.enable_code_interpreter}")
return True
def test_data_classes():
"""Test data class creation and methods."""
# Test Citation
citation = Citation(
title="Test Source",
url="https://example.com",
start_index=0,
end_index=100
)
print(f"✓ Citation created: {citation}")
# Test ReasoningStep
reasoning = ReasoningStep(text="Analyzing the query...")
print(f"✓ ReasoningStep created: {reasoning}")
# Test WebSearchCall
search = WebSearchCall(query="test query", status="completed")
print(f"✓ WebSearchCall created: {search}")
# Test CodeExecutionStep
code = CodeExecutionStep(input_code="print('hello')", output="hello")
print(f"✓ CodeExecutionStep created: {code}")
# Test MCPCall
mcp = MCPCall(name="fetch", server_label="internal", arguments={"file_id": "123"})
print(f"✓ MCPCall created: {mcp}")
# Test DeepResearchResponse
response = DeepResearchResponse(
report="This is a test report about AI.",
citations=[citation],
reasoning_steps=[reasoning],
web_searches=[search],
code_executions=[code],
mcp_calls=[mcp]
)
print(f"✓ DeepResearchResponse created")
print(f" - Report length: {len(response.report)} chars")
print(f" - Citations: {len(response.citations)}")
print(f" - Sources: {response.get_all_sources()}")
return True
def test_research_query():
"""Test actual research query (requires API key)."""
if not os.environ.get("OPENAI_API_KEY"):
print("⚠ Skipping research test - OPENAI_API_KEY not set")
return True
agent = DeepResearchAgent(
name="Healthcare Researcher",
instructions="""
You are a professional researcher preparing a structured, data-driven report.
Focus on data-rich insights with specific figures and trends.
Include inline citations and prioritize reliable sources.
""",
model="o4-mini-deep-research", # Use faster model for testing
verbose=True,
enable_code_interpreter=False
)
print("\n🔍 Starting deep research query...")
print(" (This may take several minutes)")
try:
result = agent.research(
"What are the key trends in AI adoption in healthcare in 2024?",
summary_mode="concise"
)
print(f"\n✓ Research completed!")
print(f" - Report length: {len(result.report)} characters")
print(f" - Citations found: {len(result.citations)}")
print(f" - Reasoning steps: {len(result.reasoning_steps)}")
print(f" - Web searches: {len(result.web_searches)}")
print(f" - Code executions: {len(result.code_executions)}")
# Print first 500 chars of report
print(f"\n📄 Report excerpt:")
print(f" {result.report[:500]}...")
# Print some citations
if result.citations:
print(f"\n📚 Sample citations:")
for i, c in enumerate(result.citations[:3]):
print(f" {i+1}. {c.title}: {c.url}")
# Print web searches
if result.web_searches:
print(f"\n🔎 Web searches performed:")
for s in result.web_searches[:5]:
print(f" - {s.query} ({s.status})")
return True
except Exception as e:
print(f"✗ Research failed: {e}")
return False
def test_clarify_and_rewrite():
"""Test clarifying questions and query rewriting."""
if not os.environ.get("OPENAI_API_KEY"):
print("⚠ Skipping clarify/rewrite test - OPENAI_API_KEY not set")
return True
agent = DeepResearchAgent(
name="Research Assistant",
verbose=True
)
print("\n🤔 Testing clarifying questions...")
try:
questions = agent.clarify("Help me research AI trends")
print(f"✓ Clarifying questions generated:")
print(f" {questions[:300]}...")
except Exception as e:
print(f"✗ Clarify failed: {e}")
return False
print("\n✍️ Testing query rewriting...")
try:
rewritten = agent.rewrite_query("Research AI in healthcare")
print(f"✓ Query rewritten:")
print(f" {rewritten[:300]}...")
except Exception as e:
print(f"✗ Rewrite failed: {e}")
return False
return True
def test_mcp_configuration():
"""Test MCP server configuration."""
if not os.environ.get("OPENAI_API_KEY"):
print("⚠ Skipping MCP test - OPENAI_API_KEY not set")
return True
# Test agent with MCP configuration
agent = DeepResearchAgent(
name="MCP Researcher",
instructions="You are a researcher with access to internal documents.",
mcp_servers=[
{
"label": "internal_docs",
"url": "https://example.com/mcp/sse/",
"require_approval": "never"
}
],
verbose=True
)
print(f"✓ Agent with MCP configured: {agent}")
print(f" - MCP servers: {len(agent.mcp_servers)}")
# Test tool building
tools = agent._build_tools(
web_search=True,
code_interpreter=True,
mcp_servers=agent.mcp_servers
)
print(f"✓ Tools built: {len(tools)} tools")
for t in tools:
print(f" - {t.get('type', 'unknown')}")
return True
def run_all_tests():
"""Run all tests."""
print("=" * 60)
print("DeepResearchAgent Test Suite")
print("=" * 60)
tests = [
("Import Test", test_basic_import),
("Data Classes Test", test_data_classes),
("Agent Initialization Test", test_agent_initialization),
("MCP Configuration Test", test_mcp_configuration),
("Clarify & Rewrite Test", test_clarify_and_rewrite),
("Research Query Test", test_research_query),
]
results = []
for name, test_fn in tests:
print(f"\n{'─' * 40}")
print(f"Running: {name}")
print(f"{'─' * 40}")
try:
success = test_fn()
results.append((name, success))
except Exception as e:
print(f"✗ Test failed with exception: {e}")
results.append((name, False))
# Summary
print(f"\n{'=' * 60}")
print("Test Summary")
print(f"{'=' * 60}")
passed = sum(1 for _, s in results if s)
total = len(results)
print(f"Passed: {passed}/{total}")
for name, success in results:
status = "✓" if success else "✗"
print(f" {status} {name}")
return passed == total
if __name__ == "__main__":
success = run_all_tests()
sys.exit(0 if success else 1)
@@ -0,0 +1,403 @@
"""
Tests for QueryRewriterAgent
Run with: python -m pytest tests/query_rewriter_test.py -v
"""
import pytest
from unittest.mock import patch
class TestQueryRewriterImports:
"""Test that all imports work correctly."""
def test_import_from_package(self):
"""Test importing from main package."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy, RewriteResult
assert QueryRewriterAgent is not None
assert RewriteStrategy is not None
assert RewriteResult is not None
def test_import_from_agent_module(self):
"""Test importing from agent module."""
from praisonaiagents.agent import QueryRewriterAgent, RewriteStrategy, RewriteResult
assert QueryRewriterAgent is not None
assert RewriteStrategy is not None
assert RewriteResult is not None
class TestRewriteStrategy:
"""Test RewriteStrategy enum."""
def test_strategy_values(self):
"""Test all strategy values exist."""
from praisonaiagents import RewriteStrategy
assert RewriteStrategy.BASIC.value == "basic"
assert RewriteStrategy.HYDE.value == "hyde"
assert RewriteStrategy.STEP_BACK.value == "step_back"
assert RewriteStrategy.SUB_QUERIES.value == "sub_queries"
assert RewriteStrategy.MULTI_QUERY.value == "multi_query"
assert RewriteStrategy.CONTEXTUAL.value == "contextual"
assert RewriteStrategy.AUTO.value == "auto"
class TestRewriteResult:
"""Test RewriteResult dataclass."""
def test_result_creation(self):
"""Test creating a RewriteResult."""
from praisonaiagents import RewriteResult, RewriteStrategy
result = RewriteResult(
original_query="test query",
rewritten_queries=["rewritten test query"],
strategy_used=RewriteStrategy.BASIC
)
assert result.original_query == "test query"
assert result.rewritten_queries == ["rewritten test query"]
assert result.strategy_used == RewriteStrategy.BASIC
def test_primary_query_property(self):
"""Test primary_query property."""
from praisonaiagents import RewriteResult, RewriteStrategy
result = RewriteResult(
original_query="test",
rewritten_queries=["first", "second"],
strategy_used=RewriteStrategy.MULTI_QUERY
)
assert result.primary_query == "first"
def test_primary_query_fallback(self):
"""Test primary_query falls back to original if empty."""
from praisonaiagents import RewriteResult, RewriteStrategy
result = RewriteResult(
original_query="test",
rewritten_queries=[],
strategy_used=RewriteStrategy.BASIC
)
assert result.primary_query == "test"
def test_all_queries_property(self):
"""Test all_queries property combines all queries."""
from praisonaiagents import RewriteResult, RewriteStrategy
result = RewriteResult(
original_query="original",
rewritten_queries=["rewritten"],
strategy_used=RewriteStrategy.STEP_BACK,
step_back_question="step back",
sub_queries=["sub1", "sub2"]
)
all_q = result.all_queries
assert "original" in all_q
assert "rewritten" in all_q
assert "step back" in all_q
assert "sub1" in all_q
assert "sub2" in all_q
class TestQueryRewriterAgentInit:
"""Test QueryRewriterAgent initialization."""
def test_default_initialization(self):
"""Test agent initializes with defaults."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
assert agent.name == "QueryRewriterAgent"
assert agent.model == "gpt-4o-mini"
assert not agent.verbose
assert agent.max_queries == 5
assert agent.temperature == 0.3
assert agent.max_tokens == 500
def test_custom_initialization(self):
"""Test agent initializes with custom values."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent(
name="CustomRewriter",
model="gpt-4o",
verbose=True,
max_queries=10,
temperature=0.5,
max_tokens=1000
)
assert agent.name == "CustomRewriter"
assert agent.model == "gpt-4o"
assert agent.verbose
assert agent.max_queries == 10
assert agent.temperature == 0.5
assert agent.max_tokens == 1000
def test_default_abbreviations(self):
"""Test default abbreviations are set."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
assert "AI" in agent.abbreviations
assert "ML" in agent.abbreviations
assert "RAG" in agent.abbreviations
assert agent.abbreviations["AI"] == "Artificial Intelligence"
class TestAbbreviationExpansion:
"""Test abbreviation expansion functionality."""
def test_expand_abbreviations(self):
"""Test _expand_abbreviations method."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
result = agent._expand_abbreviations("AI trends")
assert "Artificial Intelligence" in result
def test_add_abbreviation(self):
"""Test adding single abbreviation."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
agent.add_abbreviation("K8s", "Kubernetes")
assert "K8S" in agent.abbreviations
assert agent.abbreviations["K8S"] == "Kubernetes"
def test_add_abbreviations(self):
"""Test adding multiple abbreviations."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
agent.add_abbreviations({
"TF": "TensorFlow",
"PT": "PyTorch"
})
assert "TF" in agent.abbreviations
assert "PT" in agent.abbreviations
class TestQueryDetection:
"""Test query analysis methods."""
def test_is_short_query(self):
"""Test short query detection."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
assert agent._is_short_query("AI")
assert agent._is_short_query("AI trends")
assert not agent._is_short_query("What are the latest AI trends in 2025?")
def test_is_follow_up(self):
"""Test follow-up query detection."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
assert agent._is_follow_up("What about it?")
assert agent._is_follow_up("And this one?")
assert not agent._is_follow_up("What is AI?")
def test_is_complex_query(self):
"""Test complex query detection."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
assert agent._is_complex_query("What is A and what is B?")
assert agent._is_complex_query("Question one? Question two?")
assert not agent._is_complex_query("What is AI?")
class TestStrategyDetection:
"""Test automatic strategy detection."""
def test_detect_basic_for_short(self):
"""Test BASIC detected for short queries."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent()
strategy = agent._detect_strategy("AI")
assert strategy == RewriteStrategy.BASIC
def test_detect_contextual_for_followup(self):
"""Test CONTEXTUAL detected for follow-up with history."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent()
chat_history = [{"role": "user", "content": "Tell me about Python"}]
strategy = agent._detect_strategy("What about it?", chat_history)
assert strategy == RewriteStrategy.CONTEXTUAL
def test_detect_sub_queries_for_complex(self):
"""Test SUB_QUERIES detected for complex queries."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent()
strategy = agent._detect_strategy("What is A and what is B?")
assert strategy == RewriteStrategy.SUB_QUERIES
class TestJSONParsing:
"""Test JSON array parsing from LLM responses."""
def test_parse_valid_json(self):
"""Test parsing valid JSON array."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
result = agent._parse_json_array('["query1", "query2"]')
assert result == ["query1", "query2"]
def test_parse_json_in_text(self):
"""Test extracting JSON from surrounding text."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
result = agent._parse_json_array('Here are the queries: ["q1", "q2"]')
assert result == ["q1", "q2"]
def test_parse_fallback_newlines(self):
"""Test fallback to newline splitting."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
result = agent._parse_json_array("1. Query one\n2. Query two\n3. Query three")
assert len(result) >= 2
class TestRewriteWithMockedLLM:
"""Test rewrite methods with mocked LLM."""
@patch.object(__import__('praisonaiagents.agent.query_rewriter_agent', fromlist=['QueryRewriterAgent']).QueryRewriterAgent, '_call_agent')
def test_rewrite_basic(self, mock_llm):
"""Test basic rewriting with mocked LLM."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
mock_llm.return_value = "What are the current trends in AI?"
agent = QueryRewriterAgent()
result = agent.rewrite("AI trends", strategy=RewriteStrategy.BASIC)
assert result.strategy_used == RewriteStrategy.BASIC
assert len(result.rewritten_queries) > 0
mock_llm.assert_called_once()
@patch.object(__import__('praisonaiagents.agent.query_rewriter_agent', fromlist=['QueryRewriterAgent']).QueryRewriterAgent, '_call_agent')
def test_rewrite_hyde(self, mock_llm):
"""Test HyDE rewriting with mocked LLM."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
mock_llm.return_value = "Quantum computing is a type of computation..."
agent = QueryRewriterAgent()
result = agent.rewrite("What is quantum computing?", strategy=RewriteStrategy.HYDE)
assert result.strategy_used == RewriteStrategy.HYDE
assert result.hypothetical_document is not None
mock_llm.assert_called_once()
@patch.object(__import__('praisonaiagents.agent.query_rewriter_agent', fromlist=['QueryRewriterAgent']).QueryRewriterAgent, '_call_agent')
def test_rewrite_step_back(self, mock_llm):
"""Test step-back rewriting with mocked LLM."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
# First call for step-back, second for basic
mock_llm.side_effect = [
"What are the fundamentals of language models?",
"What are the differences between GPT-4 and Claude 3?"
]
agent = QueryRewriterAgent()
result = agent.rewrite("GPT-4 vs Claude 3?", strategy=RewriteStrategy.STEP_BACK)
assert result.strategy_used == RewriteStrategy.STEP_BACK
assert result.step_back_question is not None
@patch.object(__import__('praisonaiagents.agent.query_rewriter_agent', fromlist=['QueryRewriterAgent']).QueryRewriterAgent, '_call_agent')
def test_rewrite_sub_queries(self, mock_llm):
"""Test sub-query decomposition with mocked LLM."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
mock_llm.return_value = '["What is RAG?", "What are the best embedding models?"]'
agent = QueryRewriterAgent()
result = agent.rewrite("RAG setup and embedding models?", strategy=RewriteStrategy.SUB_QUERIES)
assert result.strategy_used == RewriteStrategy.SUB_QUERIES
assert result.sub_queries is not None
assert len(result.sub_queries) >= 1
@patch.object(__import__('praisonaiagents.agent.query_rewriter_agent', fromlist=['QueryRewriterAgent']).QueryRewriterAgent, '_call_agent')
def test_rewrite_multi_query(self, mock_llm):
"""Test multi-query generation with mocked LLM."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
mock_llm.return_value = '["Query 1", "Query 2", "Query 3"]'
agent = QueryRewriterAgent()
result = agent.rewrite("LLM quality?", strategy=RewriteStrategy.MULTI_QUERY, num_queries=3)
assert result.strategy_used == RewriteStrategy.MULTI_QUERY
assert len(result.rewritten_queries) >= 1
@patch.object(__import__('praisonaiagents.agent.query_rewriter_agent', fromlist=['QueryRewriterAgent']).QueryRewriterAgent, '_call_agent')
def test_rewrite_contextual(self, mock_llm):
"""Test contextual rewriting with mocked LLM."""
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
mock_llm.return_value = "How does Python's performance compare to other languages?"
agent = QueryRewriterAgent()
chat_history = [
{"role": "user", "content": "Tell me about Python"},
{"role": "assistant", "content": "Python is a programming language..."}
]
result = agent.rewrite(
"What about its performance?",
strategy=RewriteStrategy.CONTEXTUAL,
chat_history=chat_history
)
assert result.strategy_used == RewriteStrategy.CONTEXTUAL
assert "Python" in result.primary_query or len(result.rewritten_queries) > 0
class TestConvenienceMethods:
"""Test convenience methods."""
def test_convenience_methods_exist(self):
"""Test all convenience methods exist."""
from praisonaiagents import QueryRewriterAgent
agent = QueryRewriterAgent()
assert hasattr(agent, 'rewrite_basic')
assert hasattr(agent, 'rewrite_hyde')
assert hasattr(agent, 'rewrite_step_back')
assert hasattr(agent, 'rewrite_sub_queries')
assert hasattr(agent, 'rewrite_multi_query')
assert hasattr(agent, 'rewrite_contextual')
if __name__ == "__main__":
pytest.main([__file__, "-v"])
+2 -2
View File
@@ -1,5 +1,5 @@
version = 1
revision = 2
revision = 3
requires-python = ">=3.10"
resolution-markers = [
"python_full_version >= '3.13'",
@@ -2422,7 +2422,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.160"
version = "0.0.168"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
+29 -4
View File
@@ -1,9 +1,34 @@
# PraisonAI Package
This is the PraisonAI package, which serves as a wrapper for PraisonAIAgents.
## Development
It provides a simple and intuitive interface for working with AI agents and their capabilities.
```bash
# Install
uv sync
## Directory Structure
# Build
uv build
The main package code is located in the `praisonai` subdirectory.
# Publish
uv publish
```
## Version Bump
```bash
# From project root
python src/praisonai/scripts/bump_version.py 2.2.96
# With praisonaiagents dependency
python src/praisonai/scripts/bump_version.py 2.2.96 --agents 0.0.167
```
## Release
```bash
# From project root (runs uv lock, build, git tag, gh release)
python src/praisonai/scripts/release.py
# Then publish
cd src/praisonai && uv publish
```
+2 -2
View File
@@ -3,8 +3,8 @@ class Praisonai < Formula
desc "AI tools for various AI applications"
homepage "https://github.com/MervinPraison/PraisonAI"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.86.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.86.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.97.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.97.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
+320 -11
View File
@@ -28,6 +28,13 @@ AUTOGEN_AVAILABLE = False
PRAISONAI_AVAILABLE = False
TRAIN_AVAILABLE = False
try:
import importlib.util
CHAINLIT_AVAILABLE = importlib.util.find_spec("chainlit") is not None
except ImportError:
pass
def _get_chainlit_run():
"""Lazy import chainlit to avoid loading .env at startup"""
# Create necessary directories and set CHAINLIT_APP_ROOT
if "CHAINLIT_APP_ROOT" not in os.environ:
chainlit_root = os.path.join(os.path.expanduser("~"), ".praison")
@@ -39,9 +46,7 @@ try:
os.makedirs(os.path.join(chainlit_root, ".files"), exist_ok=True)
from chainlit.cli import chainlit_run
CHAINLIT_AVAILABLE = True
except ImportError:
pass
return chainlit_run
try:
import gradio as gr
@@ -509,9 +514,8 @@ class PraisonAI:
in_test_env = (
'pytest' in sys.argv[0] or
'unittest' in sys.argv[0] or
any('test' in arg for arg in sys.argv[1:3]) or # Check first few args for test indicators
'pytest' in sys.modules or
'unittest' in sys.modules
any(arg.startswith('tests.') or arg.startswith('tests/') for arg in sys.argv[1:3]) or # Check for test module paths
'PYTEST_CURRENT_TEST' in os.environ
)
# Check if we're being used as a library (not from praisonai CLI)
@@ -545,7 +549,7 @@ class PraisonAI:
return default_args
# Define special commands
special_commands = ['chat', 'code', 'call', 'realtime', 'train', 'ui', 'context']
special_commands = ['chat', 'code', 'call', 'realtime', 'train', 'ui', 'context', 'research']
parser = argparse.ArgumentParser(prog="praisonai", description="praisonAI command-line interface")
parser.add_argument("--framework", choices=["crewai", "autogen", "praisonai"], help="Specify the framework")
@@ -572,6 +576,12 @@ class PraisonAI:
parser.add_argument("--url", type=str, help="Repository URL for context analysis")
parser.add_argument("--goal", type=str, help="Goal for context engineering")
parser.add_argument("--auto-analyze", action="store_true", help="Enable automatic analysis in context engineering")
parser.add_argument("--research", action="store_true", help="Run deep research on a topic")
parser.add_argument("--query-rewrite", action="store_true", help="Rewrite query for better results (works with any command)")
parser.add_argument("--rewrite-tools", type=str, help="Tools for query rewriter (e.g., 'internet_search' or path to tools.py)")
parser.add_argument("--tools", "-t", type=str, help="Path to tools.py file for research agent")
parser.add_argument("--save", "-s", action="store_true", help="Save research output to file (output/research/)")
parser.add_argument("--verbose", "-v", action="store_true", help="Enable verbose output for research")
# If we're in a test environment, parse with empty args to avoid pytest interference
if in_test_env:
@@ -696,6 +706,29 @@ class PraisonAI:
self.handle_context_command(args.url, args.goal, getattr(args, 'auto_analyze', False))
sys.exit(0)
elif args.command == 'research':
if not PRAISONAI_AVAILABLE:
print("[red]ERROR: PraisonAI Agents is not installed. Install with:[/red]")
print("\npip install praisonaiagents\n")
sys.exit(1)
# Get the research query from remaining args
research_query = ' '.join(unknown_args) if unknown_args else None
if not research_query:
print("[red]ERROR: Research query is required[/red]")
print("Usage: praisonai research \"Your research query\"")
print(" praisonai research --model deep-research-pro \"Your query\"")
sys.exit(1)
research_model = getattr(args, 'model', None)
verbose = getattr(args, 'verbose', False)
save = getattr(args, 'save', False)
query_rewrite = getattr(args, 'query_rewrite', False)
rewrite_tools = getattr(args, 'rewrite_tools', None)
tools_path = getattr(args, 'tools', None)
self.handle_research_command(research_query, research_model, verbose, save, query_rewrite, tools_path, rewrite_tools)
sys.exit(0)
# Only check framework availability for agent-related operations
if not args.command and (args.init or args.auto or args.framework):
if not CREWAI_AVAILABLE and not AUTOGEN_AVAILABLE and not PRAISONAI_AVAILABLE:
@@ -714,10 +747,105 @@ class PraisonAI:
return args
def _rewrite_query(self, query: str, rewrite_tools: str = None, verbose: bool = False) -> str:
"""
Rewrite query using QueryRewriterAgent.
Args:
query: The query to rewrite
rewrite_tools: Tool names (comma-separated) or path to tools.py
verbose: Enable verbose output
Returns:
Rewritten query or original if rewriting fails
"""
try:
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
from rich import print
print("[bold cyan]Rewriting query for better results...[/bold cyan]")
# Load rewrite tools if specified
rewrite_tools_list = []
if rewrite_tools:
if os.path.isfile(rewrite_tools):
# Load from file
try:
import inspect
import importlib.util
spec = importlib.util.spec_from_file_location("rewrite_tools_module", rewrite_tools)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for name, obj in inspect.getmembers(module):
if inspect.isfunction(obj) and not name.startswith('_'):
rewrite_tools_list.append(obj)
if rewrite_tools_list:
print(f"[cyan]Loaded {len(rewrite_tools_list)} tools for query rewriter[/cyan]")
except Exception as e:
print(f"[yellow]Warning: Failed to load rewrite tools: {e}[/yellow]")
else:
# Treat as comma-separated tool names
try:
from praisonaiagents.tools import TOOL_MAPPINGS
import praisonaiagents.tools as tools_module
tool_names = [t.strip() for t in rewrite_tools.split(',')]
for tool_name in tool_names:
if tool_name in TOOL_MAPPINGS:
try:
tool = getattr(tools_module, tool_name)
rewrite_tools_list.append(tool)
except Exception as e:
print(f"[yellow]Warning: Failed to load rewrite tool '{tool_name}': {e}[/yellow]")
else:
print(f"[yellow]Warning: Unknown rewrite tool '{tool_name}'[/yellow]")
if rewrite_tools_list:
print(f"[cyan]Using rewrite tools: {', '.join(tool_names)}[/cyan]")
except ImportError:
print("[yellow]Warning: Could not import tools module[/yellow]")
rewriter = QueryRewriterAgent(
model="gpt-4o-mini",
verbose=verbose,
tools=rewrite_tools_list if rewrite_tools_list else None
)
result = rewriter.rewrite(query, strategy=RewriteStrategy.AUTO)
rewritten = result.primary_query
print(f"[cyan]Original:[/cyan] {query}")
print(f"[cyan]Rewritten:[/cyan] {rewritten}")
return rewritten
except ImportError:
from rich import print
print("[yellow]Warning: QueryRewriterAgent not available, using original query[/yellow]")
return query
except Exception as e:
from rich import print
print(f"[yellow]Warning: Query rewrite failed ({e}), using original query[/yellow]")
return query
def _rewrite_query_if_enabled(self, query: str) -> str:
"""
Rewrite query using QueryRewriterAgent if --query-rewrite is enabled.
Returns the rewritten query or original if rewriting is disabled/fails.
"""
if not hasattr(self, 'args') or not getattr(self.args, 'query_rewrite', False):
return query
rewrite_tools = getattr(self.args, 'rewrite_tools', None)
verbose = getattr(self.args, 'verbose', False)
return self._rewrite_query(query, rewrite_tools, verbose)
def handle_direct_prompt(self, prompt):
"""
Handle direct prompt by creating a single agent and running it.
"""
# Apply query rewriting if enabled
prompt = self._rewrite_query_if_enabled(prompt)
if PRAISONAI_AVAILABLE:
agent_config = {
"name": "DirectAgent",
@@ -791,7 +919,7 @@ class PraisonAI:
if "CHAINLIT_APP_ROOT" not in os.environ:
os.environ["CHAINLIT_APP_ROOT"] = root_path
chat_ui_path = os.path.join(os.path.dirname(praisonai.__file__), 'ui', 'chat.py')
chainlit_run([chat_ui_path])
_get_chainlit_run()([chat_ui_path])
else:
print("ERROR: Chat UI is not installed. Please install it with 'pip install \"praisonai[chat]\"' to use the chat UI.")
@@ -815,7 +943,7 @@ class PraisonAI:
else:
logging.info("Public folder already exists.")
code_ui_path = os.path.join(os.path.dirname(praisonai.__file__), 'ui', 'code.py')
chainlit_run([code_ui_path])
_get_chainlit_run()([code_ui_path])
else:
print("ERROR: Code UI is not installed. Please install it with 'pip install \"praisonai[code]\"' to use the code UI.")
@@ -861,7 +989,7 @@ class PraisonAI:
else:
logging.info("Public folder already exists.")
chainlit_ui_path = os.path.join(os.path.dirname(praisonai.__file__), 'ui', 'agents.py')
chainlit_run([chainlit_ui_path])
_get_chainlit_run()([chainlit_ui_path])
else:
print("ERROR: Chainlit is not installed. Please install it with 'pip install \"praisonai[ui]\"' to use the UI.")
@@ -885,7 +1013,7 @@ class PraisonAI:
else:
logging.info("Public folder already exists.")
realtime_ui_path = os.path.join(os.path.dirname(praisonai.__file__), 'ui', 'realtime.py')
chainlit_run([realtime_ui_path])
_get_chainlit_run()([realtime_ui_path])
else:
print("ERROR: Realtime UI is not installed. Please install it with 'pip install \"praisonai[realtime]\"' to use the realtime UI.")
@@ -933,6 +1061,187 @@ class PraisonAI:
print(f"[red]ERROR: Context engineering failed: {e}[/red]")
sys.exit(1)
def handle_research_command(self, query: str, model: str = None, verbose: bool = False, save: bool = False, query_rewrite: bool = False, tools_path: str = None, rewrite_tools: str = None) -> str:
"""
Handle the research command by creating a DeepResearchAgent and running it.
Args:
query: Research query/topic
model: Model for deep research (optional, defaults to o4-mini-deep-research)
verbose: Enable verbose output (default: False)
save: Save output to file (default: False)
query_rewrite: Rewrite query before research (default: False)
tools_path: Path to tools.py file with custom tools (default: None)
rewrite_tools: Tools for query rewriter (tool names or file path)
Returns:
str: Research report
"""
try:
from praisonaiagents import DeepResearchAgent
# Suppress logging unless verbose
if not verbose:
logging.getLogger('google').setLevel(logging.WARNING)
logging.getLogger('google.genai').setLevel(logging.WARNING)
logging.getLogger('httpx').setLevel(logging.WARNING)
logging.getLogger('httpcore').setLevel(logging.WARNING)
# Rewrite query if requested
if query_rewrite:
query = self._rewrite_query(query, rewrite_tools, verbose)
print("[bold green]Starting Deep Research...[/bold green]")
print(f"Query: {query}")
# Default model if not specified
if not model:
model = "o4-mini-deep-research"
print(f"Model: {model}")
# Load tools if specified
tools_list = []
if tools_path:
# Check if it's a file path or comma-separated tool names
if os.path.isfile(tools_path):
# Load from file
try:
import inspect
spec = importlib.util.spec_from_file_location("tools_module", tools_path)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Get all callable functions from the module
for name, obj in inspect.getmembers(module):
if inspect.isfunction(obj) and not name.startswith('_'):
tools_list.append(obj)
if tools_list:
print(f"[cyan]Loaded {len(tools_list)} tools from {tools_path}[/cyan]")
except Exception as e:
print(f"[yellow]Warning: Failed to load tools from {tools_path}: {e}[/yellow]")
else:
# Treat as comma-separated tool names (e.g., "internet_search,wiki_search")
try:
from praisonaiagents.tools import TOOL_MAPPINGS
import praisonaiagents.tools as tools_module
tool_names = [t.strip() for t in tools_path.split(',')]
for tool_name in tool_names:
if tool_name in TOOL_MAPPINGS:
try:
tool = getattr(tools_module, tool_name)
tools_list.append(tool)
except Exception as e:
print(f"[yellow]Warning: Failed to load tool '{tool_name}': {e}[/yellow]")
else:
print(f"[yellow]Warning: Unknown tool '{tool_name}'[/yellow]")
if tools_list:
print(f"[cyan]Loaded {len(tools_list)} built-in tools: {', '.join(tool_names)}[/cyan]")
except ImportError:
print("[yellow]Warning: Could not import tools module[/yellow]")
# If tools are provided, use Agent with tools first, then DeepResearchAgent
if tools_list:
from praisonaiagents import Agent, Task, PraisonAIAgents
# Create a research assistant agent with tools
research_assistant = Agent(
name="Research Assistant",
role="Information Gatherer",
goal="Gather relevant information using available tools",
backstory="You are an expert at using tools to gather information for research.",
tools=tools_list,
llm="gpt-4o-mini",
verbose=False
)
# Create task to gather initial information
gather_task = Task(
description=f"Use your tools to gather relevant information about: {query}",
expected_output="A summary of information gathered from the tools",
agent=research_assistant
)
print("[cyan]Gathering information with tools...[/cyan]")
agents = PraisonAIAgents(agents=[research_assistant], tasks=[gather_task], verbose=0)
tool_results = agents.start()
# Enhance query with tool results
enhanced_query = f"{query}\n\nAdditional context from tools:\n{tool_results}"
print("[cyan]Tools context gathered, starting deep research...[/cyan]")
# Create DeepResearchAgent
agent = DeepResearchAgent(model=model)
result = agent.research(enhanced_query)
else:
# Create DeepResearchAgent (verbose=True is default for streaming output)
agent = DeepResearchAgent(model=model)
# Execute the research
result = agent.research(query)
print("\n[bold green]Research Complete![/bold green]")
print("\n" + "="*60)
print(result.report)
print("="*60)
# Show citations if available
if result.citations:
print(f"\n[bold]Citations ({len(result.citations)}):[/bold]")
for i, citation in enumerate(result.citations, 1):
title = getattr(citation, 'title', 'Untitled')
url = getattr(citation, 'url', '')
print(f" {i}. {title}")
if url:
print(f" {url}")
# Save output to file if --save flag is set
if save:
import re
# Get first 10 words from query for filename
words = query.split()[:10]
filename_base = ' '.join(words)
# Sanitize filename: remove invalid characters
filename_base = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '', filename_base)
filename_base = filename_base.strip()[:100] # Limit length
if not filename_base:
filename_base = "research_output"
# Create output directory
output_dir = os.path.join(os.getcwd(), "output", "research")
os.makedirs(output_dir, exist_ok=True)
# Build markdown content
md_content = f"# {query}\n\n"
md_content += result.report
if result.citations:
md_content += "\n\n## Citations\n\n"
for i, citation in enumerate(result.citations, 1):
title = getattr(citation, 'title', 'Untitled')
url = getattr(citation, 'url', '')
if url:
md_content += f"{i}. [{title}]({url})\n"
else:
md_content += f"{i}. {title}\n"
# Save to file
output_path = os.path.join(output_dir, f"{filename_base}.md")
with open(output_path, 'w', encoding='utf-8') as f:
f.write(md_content)
print(f"\n[bold green]Saved to:[/bold green] {output_path}")
return result.report
except ImportError as e:
print(f"[red]ERROR: Failed to import DeepResearchAgent: {e}[/red]")
print("Make sure praisonaiagents is installed: pip install praisonaiagents")
sys.exit(1)
except Exception as e:
print(f"[red]ERROR: Research failed: {e}[/red]")
sys.exit(1)
if __name__ == "__main__":
praison_ai = PraisonAI()
praison_ai.main()
+1 -1
View File
@@ -57,7 +57,7 @@ class CloudDeployer:
file.write("FROM python:3.11-slim\n")
file.write("WORKDIR /app\n")
file.write("COPY . .\n")
file.write("RUN pip install flask praisonai==2.2.86 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.2.97 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+9 -5
View File
@@ -138,11 +138,15 @@ class PraisonAIModel:
"Please install with 'pip install langchain-anthropic'"
)
elif OPENAI_AVAILABLE:
return ChatOpenAI(
model=self.model_name,
api_key=self.api_key,
base_url=self.base_url,
)
chat_kwargs = {
"model": self.model_name,
"api_key": self.api_key,
"base_url": self.base_url,
}
# Certain OpenAI models (e.g., gpt-5-* family) only allow temperature=1
if isinstance(self.model_name, str) and self.model_name.startswith("gpt-5"):
chat_kwargs["temperature"] = 1
return ChatOpenAI(**chat_kwargs)
else:
raise ImportError(
"Required Langchain Integration 'langchain-openai' not found. "
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.0.1"
__version__ = "2.2.97"
+12 -195
View File
@@ -1,9 +1,9 @@
[project]
name = "PraisonAI"
version = "2.2.86"
dynamic = ["version"]
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
readme = "README.md"
license = ""
license = {text = "MIT"}
requires-python = ">=3.10"
authors = [
{ name = "Mervin Praison" }
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.0.160",
"praisonaiagents>=0.0.168",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
@@ -90,7 +90,7 @@ call = [
"openai>=1.54.0",
]
train = []
crewai = ["crewai>=0.148.0", "praisonai-tools>=0.0.22"]
crewai = ["crewai>=0.157.0", "praisonai-tools>=0.0.22"]
autogen = ["pyautogen==0.2.29", "praisonai-tools>=0.0.22", "crewai"]
autogen-v4 = [
"autogen-agentchat>=0.4.0",
@@ -100,200 +100,17 @@ autogen-v4 = [
"crewai"
]
[tool.poetry]
name = "PraisonAI"
version = "2.2.86"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
authors = ["Mervin Praison"]
license = ""
readme = "README.md"
[tool.poetry.urls]
[project.urls]
Homepage = "https://docs.praison.ai"
Repository = "https://github.com/mervinpraison/PraisonAI"
[tool.setuptools]
packages = ["praisonai"]
[tool.poetry.dependencies]
python = ">=3.10,<3.13"
rich = ">=13.7"
markdown = ">=3.5"
pyparsing = ">=3.0.0"
praisonaiagents = ">=0.0.160"
python-dotenv = ">=0.19.0"
instructor = ">=1.3.3"
PyYAML = ">=6.0"
mcp = ">=1.6.0"
pyautogen = {version = "==0.2.29", optional = true}
autogen-agentchat = {version = ">=0.4.0", optional = true}
autogen-ext = {version = ">=0.4.0", optional = true}
autogen-core = {version = ">=0.4.0", optional = true}
crewai = {version = ">=0.148.0", optional = true}
praisonai-tools = {version = ">=0.0.22", optional = true}
chainlit = {version = "==2.5.5", optional = true}
gradio = {version = ">=4.26.0", optional = true}
flask = {version = ">=3.0.0", optional = true}
agentops = {version = ">=0.3.12", optional = true}
langchain-google-genai = {version = ">=2.1.0", optional = true}
langchain-anthropic = {version = ">=0.3.0", optional = true}
langchain-openai = {version = ">=0.2.1,<0.3.0", optional = true}
langchain-cohere = {version = ">=0.3.0,<0.4.0", optional = true}
litellm = {version = ">=1.72.6", optional = true}
aiosqlite= {version = ">=0.20.0", optional = true}
greenlet = {version = ">=3.0.3", optional = true}
tavily-python = {version = "==0.5.0", optional=true}
crawl4ai = {version = ">=0.7.0", optional = true}
websockets = {version = ">=12.0", optional = true}
plotly = {version = ">=5.24.0", optional = true}
yfinance = {version = ">=0.2.44", optional = true}
duckduckgo_search = {version = ">=6.3.0", optional = true}
twilio = {version = ">=7.0.0", optional = true}
fastapi = {version = ">=0.95.0", optional = true}
uvicorn = {version = ">=0.20.0", optional = true}
flaml = {version = ">=2.3.1", extras = ["automl"], optional = true}
pyngrok = {version = ">=1.4.0", optional = true}
sqlalchemy = {version = ">=2.0.36", optional = true}
playwright = {version = ">=1.47.0", optional = true}
openai = {version = ">=1.54.0", optional = true}
pydantic = {version = "<=2.10.1", optional = true}
# unsloth = {version = ">=2024.11.7", extras = ["colab-new"], optional = true}
[tool.poetry.group.docs.dependencies]
mkdocs = "*"
markdown-include = "*"
mkdocs-material = "*"
mkdocs-jupyter = "*"
mkdocs-glightbox = "*"
pymdown-extensions = "*"
Pygments = "*"
mkdocstrings = "*"
mkdocs-apidoc = "*"
mkdocstrings-python = "*"
pdoc3 = "*"
[tool.poetry.group.test.dependencies]
pytest = "8.2.2"
pytest-asyncio = ">=0.26.0"
pre-commit = "3.7.1"
unittest-xml-reporting = "3.2.0"
xmlrunner = "*"
unittest2 = "*"
[tool.poetry.group.dev.dependencies]
pytest = "8.2.2"
pytest-asyncio = ">=0.26.0"
pre-commit = "3.7.1"
unittest-xml-reporting = "3.2.0"
mkdocs = "*"
markdown-include = "*"
mkdocs-material = "*"
mkdocs-jupyter = "*"
mkdocs-glightbox = "*"
pymdown-extensions = "*"
Pygments = "*"
mkdocstrings = "*"
mkdocs-apidoc = "*"
mkdocstrings-python = "*"
pdoc3 = "*"
xmlrunner = "*"
unittest2 = "*"
chainlit = "==2.5.5"
gradio = ">=4.26.0"
flask = ">=3.0.0"
agentops = ">=0.3.12"
langchain-google-genai = ">=2.1.0"
langchain-anthropic = ">=0.3.0"
langchain-openai = ">=0.2.1,<0.3.0"
langchain-cohere = ">=0.3.0,<0.4.0"
litellm = ">=1.72.6"
aiosqlite = ">=0.20.0"
greenlet = ">=3.0.3"
[build-system]
requires = [
"poetry-core",
"setuptools>=42",
]
build-backend = "poetry.core.masonry.api"
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"
[tool.setuptools.dynamic]
version = {attr = "praisonai.version.__version__"}
[tool.poetry.scripts]
praisonai = "praisonai.__main__:main"
setup-conda-env = "setup.setup_conda_env:main"
praisonai-call = "praisonai.api.call:main"
[tool.poetry.extras]
ui = [
"chainlit",
"aiosqlite",
"greenlet",
"sqlalchemy",
"pydantic"
]
gradio = ["gradio"]
api = ["flask"]
agentops = ["agentops"]
google = ["langchain-google-genai"]
openai = ["langchain-openai"]
anthropic = ["langchain-anthropic"]
cohere = ["langchain-cohere"]
chat = [
"chainlit",
"litellm",
"aiosqlite",
"greenlet",
"tavily-python",
"crawl4ai",
"sqlalchemy",
"playwright",
"rich",
"pydantic"
]
code = [
"chainlit",
"litellm",
"aiosqlite",
"greenlet",
"tavily-python",
"crawl4ai",
"sqlalchemy",
"playwright",
"pydantic"
]
train = []
realtime = [
"chainlit",
"litellm",
"aiosqlite",
"greenlet",
"tavily-python",
"crawl4ai",
"websockets",
"plotly",
"yfinance",
"duckduckgo_search",
"sqlalchemy"
]
call = [
"twilio",
"fastapi",
"uvicorn",
"websockets",
"flaml",
"pyngrok",
"rich",
"openai",
]
crewai = ["crewai", "praisonai-tools"]
autogen = ["pyautogen", "praisonai-tools", "crewai"]
autogen-v4 = ["autogen-agentchat", "autogen-ext", "autogen-core", "praisonai-tools", "crewai"]
[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
style = "semver"
[tool.poetry.build]
generate-setup-file = false
script = "praisonai/setup/post_install.py"
[tool.setuptools.packages.find]
where = ["."]
include = ["praisonai*"]
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Version bump script for PraisonAI package.
This script updates the version number in all required locations:
- praisonai/version.py (single source of truth for Python package)
- praisonai/deploy.py (Dockerfile template)
- ../../docker/Dockerfile, Dockerfile.chat, Dockerfile.dev, Dockerfile.ui
- praisonai.rb (Homebrew formula)
Usage:
python src/praisonai/scripts/bump_version.py 2.2.96
Or with optional praisonaiagents version:
python src/praisonai/scripts/bump_version.py 2.2.96 --agents 0.0.167
"""
import re
import sys
import argparse
from pathlib import Path
def get_project_root() -> Path:
"""Get the project root directory (praisonai-package)."""
# scripts/ -> src/praisonai/ -> src/ -> praisonai-package/
return Path(__file__).parent.parent.parent.parent
def update_file(filepath: Path, patterns: list[tuple[str, str]]) -> bool:
"""Update a file with the given regex patterns and replacements."""
if not filepath.exists():
print(f" ⚠️ File not found: {filepath}")
return False
content = filepath.read_text()
original = content
for pattern, replacement in patterns:
content = re.sub(pattern, replacement, content)
if content != original:
filepath.write_text(content)
print(f" ✅ Updated: {filepath.relative_to(get_project_root())}")
return True
else:
print(f" ⏭️ No changes: {filepath.relative_to(get_project_root())}")
return False
def bump_version(new_version: str, agents_version: str | None = None):
"""Bump version in all required files."""
root = get_project_root()
print(f"\n🚀 Bumping PraisonAI version to {new_version}\n")
praisonai_dir = root / "src/praisonai"
# 1. Update version.py (single source of truth)
print("📦 Python Package:")
update_file(
praisonai_dir / "praisonai/version.py",
[(r'__version__ = "[^"]+"', f'__version__ = "{new_version}"')]
)
# 2. Update deploy.py (Dockerfile template)
print("\n🐳 Deploy Script:")
update_file(
praisonai_dir / "praisonai/deploy.py",
[(r'praisonai==[0-9.]+', f'praisonai=={new_version}')]
)
# 3. Update Dockerfiles
print("\n🐳 Dockerfiles:")
dockerfiles = [
"docker/Dockerfile",
"docker/Dockerfile.chat",
"docker/Dockerfile.dev",
"docker/Dockerfile.ui",
]
for dockerfile in dockerfiles:
update_file(
root / dockerfile,
[(r'"praisonai>=[0-9.]+"', f'"praisonai>={new_version}"')]
)
# 4. Update Homebrew formula
print("\n🍺 Homebrew Formula:")
update_file(
praisonai_dir / "praisonai.rb",
[(r'v[0-9]+\.[0-9]+\.[0-9]+', f'v{new_version}')]
)
# 5. Update praisonaiagents dependency if specified
if agents_version:
print(f"\n📦 Updating praisonaiagents dependency to {agents_version}:")
update_file(
praisonai_dir / "pyproject.toml",
[(r'praisonaiagents>=[0-9.]+', f'praisonaiagents>={agents_version}')]
)
print("\n✨ Version bump complete!")
print("\nNext steps:")
print(" 1. Run: cd src/praisonai && uv lock")
print(" 2. Run: cd src/praisonai && uv build")
print(f" 3. Commit changes: git add -A && git commit -m 'Bump version to {new_version}'")
print(f" 4. Tag release: git tag v{new_version}")
print(" 5. Publish: cd src/praisonai && uv publish")
def main():
parser = argparse.ArgumentParser(
description="Bump PraisonAI version in all required files"
)
parser.add_argument(
"version",
help="New version number (e.g., 2.2.96)"
)
parser.add_argument(
"--agents", "-a",
help="Optional: Update praisonaiagents dependency version (e.g., 0.0.167)",
default=None
)
args = parser.parse_args()
# Validate version format
if not re.match(r'^\d+\.\d+\.\d+$', args.version):
print(f"❌ Invalid version format: {args.version}")
print(" Expected format: X.Y.Z (e.g., 2.2.96)")
sys.exit(1)
if args.agents and not re.match(r'^\d+\.\d+\.\d+$', args.agents):
print(f"❌ Invalid agents version format: {args.agents}")
print(" Expected format: X.Y.Z (e.g., 0.0.167)")
sys.exit(1)
bump_version(args.version, args.agents)
if __name__ == "__main__":
main()
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""
Release script for PraisonAI package.
Usage:
python src/praisonai/scripts/release.py
This script:
1. Reads version from praisonai/version.py
2. Runs uv lock
3. Runs uv build
4. Commits changes
5. Creates git tag
6. Pushes to GitHub
7. Creates GitHub release (latest)
"""
import subprocess
import sys
from pathlib import Path
def get_project_root() -> Path:
"""Get the project root directory (praisonai-package)."""
return Path(__file__).parent.parent.parent.parent
def get_praisonai_dir() -> Path:
"""Get the praisonai package directory."""
return get_project_root() / "src/praisonai"
def get_version() -> str:
"""Read version from version.py."""
version_file = get_praisonai_dir() / "praisonai/version.py"
content = version_file.read_text()
for line in content.splitlines():
if line.startswith("__version__"):
return line.split('"')[1]
raise ValueError("Could not find version in version.py")
def run(cmd: list[str], cwd: Path | None = None, check: bool = True) -> subprocess.CompletedProcess:
"""Run a command and print it."""
print(f"$ {' '.join(cmd)}")
result = subprocess.run(cmd, cwd=cwd, capture_output=True, text=True)
if result.stdout:
print(result.stdout)
if result.stderr:
print(result.stderr, file=sys.stderr)
if check and result.returncode != 0:
print(f"❌ Command failed with exit code {result.returncode}")
sys.exit(1)
return result
def main():
root = get_project_root()
praisonai_dir = get_praisonai_dir()
version = get_version()
tag = f"v{version}"
print(f"\n🚀 Releasing PraisonAI {tag}\n")
# 1. uv lock
print("📦 Running uv lock...")
run(["uv", "lock"], cwd=praisonai_dir)
# 2. uv build
print("\n🔨 Running uv build...")
run(["uv", "build"], cwd=praisonai_dir)
# 3. Git add and commit
print("\n📝 Committing changes...")
run(["git", "add", "-A"], cwd=root)
run(["git", "commit", "-m", f"Release {tag}"], cwd=root, check=False)
# 4. Create git tag
print(f"\n🏷️ Creating tag {tag}...")
run(["git", "tag", "-f", tag], cwd=root)
# 5. Push to GitHub
print("\n⬆️ Pushing to GitHub...")
run(["git", "push"], cwd=root)
run(["git", "push", "--tags", "-f"], cwd=root)
# 6. Create GitHub release
print(f"\n🎉 Creating GitHub release {tag}...")
run([
"gh", "release", "create", tag,
"--title", f"PraisonAI {tag}",
"--notes", f"Release {tag}",
"--latest"
], cwd=root)
print(f"\n✅ Released PraisonAI {tag}")
print("\nNext step:")
print(" cd src/praisonai && uv publish")
if __name__ == "__main__":
main()
@@ -75,7 +75,8 @@ roles:
def test_autogen_environment_check(self):
"""Verify AutoGen environment is properly configured"""
# Check API key is available
assert os.getenv("OPENAI_API_KEY"), "OPENAI_API_KEY required for real tests"
if not os.getenv("OPENAI_API_KEY"):
pytest.skip("OPENAI_API_KEY required for real tests")
# Check AutoGen can be imported
try:
@@ -0,0 +1,275 @@
"""
Tests for QueryRewriterAgent CLI integration
Run with: python -m pytest tests/unit/test_query_rewriter_cli.py -v
"""
import pytest
from unittest.mock import patch, MagicMock
import argparse
class TestQueryRewriterCLIArgs:
"""Test CLI argument parsing for query rewriter."""
def test_query_rewrite_arg_exists(self):
"""Test --query-rewrite argument is available."""
from praisonai.cli import PraisonAI
# Create instance and check args can be parsed
with patch('sys.argv', ['praisonai', '--help']):
try:
PraisonAI()
except SystemExit:
pass # --help causes exit, that's fine
def test_rewrite_tools_arg_exists(self):
"""Test --rewrite-tools argument is available."""
from praisonai.cli import PraisonAI
with patch('sys.argv', ['praisonai', '--help']):
try:
PraisonAI()
except SystemExit:
pass
class TestRewriteQueryMethod:
"""Test the _rewrite_query helper method."""
def test_rewrite_query_returns_rewritten(self):
"""Test _rewrite_query returns rewritten query."""
from praisonai.cli import PraisonAI
# Setup mock
mock_result = MagicMock()
mock_result.primary_query = "What are the current trends in artificial intelligence?"
mock_agent = MagicMock()
mock_agent.rewrite.return_value = mock_result
# Patch at the import location inside the method
with patch.dict('sys.modules', {'praisonaiagents': MagicMock()}):
import sys
sys.modules['praisonaiagents'].QueryRewriterAgent = MagicMock(return_value=mock_agent)
sys.modules['praisonaiagents'].RewriteStrategy = MagicMock()
praison = PraisonAI()
result = praison._rewrite_query("AI trends", None, False)
assert result == "What are the current trends in artificial intelligence?"
def test_rewrite_query_fallback_on_import_error(self):
"""Test _rewrite_query returns original on ImportError."""
from praisonai.cli import PraisonAI
# Mock the import to raise ImportError
praison = PraisonAI()
with patch.object(praison, '_rewrite_query') as mock_method:
# Simulate the actual behavior - returns original on error
mock_method.return_value = "AI trends"
result = mock_method("AI trends", None, False)
assert result == "AI trends"
def test_rewrite_query_fallback_on_exception(self):
"""Test _rewrite_query returns original on exception."""
from praisonai.cli import PraisonAI
# Patch to raise exception
with patch.dict('sys.modules', {'praisonaiagents': MagicMock()}):
import sys
sys.modules['praisonaiagents'].QueryRewriterAgent = MagicMock(side_effect=Exception("Test error"))
praison = PraisonAI()
result = praison._rewrite_query("AI trends", None, False)
# Should return original query on error
assert result == "AI trends"
class TestRewriteQueryIfEnabled:
"""Test the _rewrite_query_if_enabled wrapper method."""
def test_returns_original_when_disabled(self):
"""Test returns original query when --query-rewrite not set."""
from praisonai.cli import PraisonAI
praison = PraisonAI()
praison.args = argparse.Namespace(query_rewrite=False)
result = praison._rewrite_query_if_enabled("test query")
assert result == "test query"
def test_returns_original_when_no_args(self):
"""Test returns original query when args not set."""
from praisonai.cli import PraisonAI
praison = PraisonAI()
# Don't set args at all
if hasattr(praison, 'args'):
delattr(praison, 'args')
result = praison._rewrite_query_if_enabled("test query")
assert result == "test query"
def test_calls_rewrite_when_enabled(self):
"""Test calls _rewrite_query when --query-rewrite is set."""
from praisonai.cli import PraisonAI
praison = PraisonAI()
praison.args = argparse.Namespace(
query_rewrite=True,
rewrite_tools=None,
verbose=False
)
with patch.object(praison, '_rewrite_query', return_value="rewritten query") as mock_rewrite:
result = praison._rewrite_query_if_enabled("original query")
mock_rewrite.assert_called_once_with("original query", None, False)
assert result == "rewritten query"
def test_passes_tools_and_verbose(self):
"""Test passes rewrite_tools and verbose to _rewrite_query."""
from praisonai.cli import PraisonAI
praison = PraisonAI()
praison.args = argparse.Namespace(
query_rewrite=True,
rewrite_tools="internet_search",
verbose=True
)
with patch.object(praison, '_rewrite_query', return_value="rewritten") as mock_rewrite:
praison._rewrite_query_if_enabled("query")
mock_rewrite.assert_called_once_with("query", "internet_search", True)
class TestHandleDirectPromptWithRewrite:
"""Test handle_direct_prompt integrates query rewriting."""
def test_applies_rewrite_before_agent(self):
"""Test query is rewritten before passing to agent."""
from praisonai.cli import PraisonAI
praison = PraisonAI()
praison.args = argparse.Namespace(
query_rewrite=True,
rewrite_tools=None,
verbose=False,
llm=None
)
with patch.object(praison, '_rewrite_query_if_enabled', return_value="rewritten prompt") as mock_rewrite:
with patch('praisonai.cli.PRAISONAI_AVAILABLE', True):
with patch('praisonai.cli.PraisonAgent') as mock_agent_class:
mock_agent = MagicMock()
mock_agent.start.return_value = "result"
mock_agent_class.return_value = mock_agent
praison.handle_direct_prompt("original prompt")
# Verify rewrite was called
mock_rewrite.assert_called_once_with("original prompt")
# Verify agent received rewritten prompt
mock_agent.start.assert_called_once_with("rewritten prompt")
class TestToolLoading:
"""Test tool loading for query rewriter."""
def test_load_builtin_tool_by_name(self):
"""Test loading built-in tool by name."""
from praisonai.cli import PraisonAI
# Setup mocks
mock_result = MagicMock()
mock_result.primary_query = "rewritten"
mock_agent = MagicMock()
mock_agent.rewrite.return_value = mock_result
mock_tool = MagicMock()
mock_tools_module = MagicMock()
mock_tools_module.TOOL_MAPPINGS = {'internet_search': 'praisonaiagents.tools'}
mock_tools_module.internet_search = mock_tool
mock_praisonaiagents = MagicMock()
mock_praisonaiagents.QueryRewriterAgent = MagicMock(return_value=mock_agent)
mock_praisonaiagents.RewriteStrategy = MagicMock()
mock_praisonaiagents.tools = mock_tools_module
with patch.dict('sys.modules', {
'praisonaiagents': mock_praisonaiagents,
'praisonaiagents.tools': mock_tools_module
}):
praison = PraisonAI()
result = praison._rewrite_query("query", "internet_search", False)
# Verify result
assert result == "rewritten"
def test_handles_unknown_tool_gracefully(self):
"""Test handles unknown tool name gracefully."""
from praisonai.cli import PraisonAI
# Setup mocks
mock_result = MagicMock()
mock_result.primary_query = "rewritten"
mock_agent = MagicMock()
mock_agent.rewrite.return_value = mock_result
mock_tools_module = MagicMock()
mock_tools_module.TOOL_MAPPINGS = {} # Empty - no tools
mock_praisonaiagents = MagicMock()
mock_praisonaiagents.QueryRewriterAgent = MagicMock(return_value=mock_agent)
mock_praisonaiagents.RewriteStrategy = MagicMock()
mock_praisonaiagents.tools = mock_tools_module
with patch.dict('sys.modules', {
'praisonaiagents': mock_praisonaiagents,
'praisonaiagents.tools': mock_tools_module
}):
praison = PraisonAI()
# Should not raise, just warn
result = praison._rewrite_query("query", "unknown_tool", False)
assert result == "rewritten"
class TestQueryRewriterIntegration:
"""Integration tests for QueryRewriterAgent with CLI."""
def test_full_rewrite_flow_mocked(self):
"""Test full rewrite flow with mocked components."""
from praisonai.cli import PraisonAI
# Setup mocks
mock_result = MagicMock()
mock_result.primary_query = "What are the latest developments in AI technology?"
mock_agent = MagicMock()
mock_agent.rewrite.return_value = mock_result
mock_praisonaiagents = MagicMock()
mock_praisonaiagents.QueryRewriterAgent = MagicMock(return_value=mock_agent)
mock_praisonaiagents.RewriteStrategy = MagicMock()
with patch.dict('sys.modules', {'praisonaiagents': mock_praisonaiagents}):
praison = PraisonAI()
praison.args = argparse.Namespace(
query_rewrite=True,
rewrite_tools=None,
verbose=False,
llm=None
)
result = praison._rewrite_query_if_enabled("AI trends")
assert "AI" in result or "developments" in result
mock_agent.rewrite.assert_called_once()
if __name__ == "__main__":
pytest.main([__file__, "-v"])
+25 -13
View File
@@ -1,5 +1,5 @@
version = 1
revision = 2
revision = 3
requires-python = ">=3.10"
resolution-markers = [
"python_full_version >= '3.13'",
@@ -905,7 +905,7 @@ wheels = [
[[package]]
name = "crewai"
version = "0.148.0"
version = "0.157.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "appdirs" },
@@ -924,6 +924,7 @@ dependencies = [
{ name = "opentelemetry-exporter-otlp-proto-http" },
{ name = "opentelemetry-sdk" },
{ name = "pdfplumber" },
{ name = "portalocker" },
{ name = "pydantic" },
{ name = "pyjwt" },
{ name = "python-dotenv" },
@@ -934,9 +935,9 @@ dependencies = [
{ name = "tomli-w" },
{ name = "uv" },
]
sdist = { url = "https://files.pythonhosted.org/packages/db/46/3247312d55b1d5887d7ce6d0a3cc39c6dc118452c1a1fb9eaaa9d121a5b4/crewai-0.148.0.tar.gz", hash = "sha256:a713477cebc98a641c8dfda0f6415b6449143848fbdf91fa6aa0f90a0e726a49", size = 6315505, upload-time = "2025-07-16T19:36:27.26Z" }
sdist = { url = "https://files.pythonhosted.org/packages/c9/fe/a469d356ddaa3adea1cfffeac965412dc3a53ebcf991641cf4776030cede/crewai-0.157.0.tar.gz", hash = "sha256:947c819fa7bf155ae065bfaae600216e43b260b9b34a07b2098d7d221236fa26", size = 6341895, upload-time = "2025-08-06T21:48:16.461Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bb/6f/8d0af8154b9b97d0207f76cd8607721536afd22fabef9702ee664ff27923/crewai-0.148.0-py3-none-any.whl", hash = "sha256:6865355d96493db63f29064eefe6397d27be2a6729cf3957aa6a90d7190ee50f", size = 365343, upload-time = "2025-07-16T19:36:24.553Z" },
{ url = "https://files.pythonhosted.org/packages/20/97/bdc70fb7f27d44b98b97475e59fa75c155e0753ef4fd9848e1d0dc90e5a2/crewai-0.157.0-py3-none-any.whl", hash = "sha256:c34e844c8c92b78219cb23e96ff10561d7d5bfa068d44f08424c8dc6f36fc456", size = 375821, upload-time = "2025-08-06T21:48:14.354Z" },
]
[[package]]
@@ -2319,7 +2320,7 @@ wheels = [
[[package]]
name = "litellm"
version = "1.72.6"
version = "1.74.9"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -2334,9 +2335,9 @@ dependencies = [
{ name = "tiktoken" },
{ name = "tokenizers" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8d/15/df75f278fd998f6d6900f692b9de2fba2814b316c123c99072a813668aac/litellm-1.72.6.tar.gz", hash = "sha256:4e5c7e4273b09b765302d2faaec30f77b42255c0055b427b55ea02b8092b8582", size = 8393603, upload-time = "2025-06-14T21:43:11.023Z" }
sdist = { url = "https://files.pythonhosted.org/packages/6d/5d/646bebdb4769d77e6a018b9152c9ccf17afe15d0f88974f338d3f2ee7c15/litellm-1.74.9.tar.gz", hash = "sha256:4a32eff70342e1aee4d1cbf2de2a6ed64a7c39d86345c58d4401036af018b7de", size = 9660510, upload-time = "2025-07-28T16:42:39.297Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/96/c9/4aae0b77632279eef9716dbcb98edd8b36c08a9da070e2470ca9c410c0f8/litellm-1.72.6-py3-none-any.whl", hash = "sha256:e0ae98d25db4910e78b1a0a604f24c0d6875f6cdea02426b264a45d4fbdb8c46", size = 8302810, upload-time = "2025-06-14T21:43:08.628Z" },
{ url = "https://files.pythonhosted.org/packages/5f/e4/f1546746049c99c6b8b247e2f34485b9eae36faa9322b84e2a17262e6712/litellm-1.74.9-py3-none-any.whl", hash = "sha256:ab8f8a6e4d8689d3c7c4f9c3bbc7e46212cc3ebc74ddd0f3c0c921bb459c9874", size = 8740449, upload-time = "2025-07-28T16:42:36.8Z" },
]
[[package]]
@@ -4013,6 +4014,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" },
]
[[package]]
name = "portalocker"
version = "2.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pywin32", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1f/f8/969e6f280201b40b31bcb62843c619f343dcc351dff83a5891530c9dd60e/portalocker-2.7.0.tar.gz", hash = "sha256:032e81d534a88ec1736d03f780ba073f047a06c478b06e2937486f334e955c51", size = 20183, upload-time = "2023-01-18T23:36:14.436Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/8c/df/d4f711d168524f5aebd7fb30969eaa31e3048cf8979688cde3b08f6e5eb8/portalocker-2.7.0-py2.py3-none-any.whl", hash = "sha256:a07c5b4f3985c3cf4798369631fb7011adb498e2a46d8440efc75a8f29a0f983", size = 15502, upload-time = "2023-01-18T23:36:12.849Z" },
]
[[package]]
name = "posthog"
version = "3.7.4"
@@ -4031,7 +4044,6 @@ wheels = [
[[package]]
name = "praisonai"
version = "2.2.86"
source = { editable = "." }
dependencies = [
{ name = "instructor" },
@@ -4157,7 +4169,7 @@ requires-dist = [
{ name = "crawl4ai", marker = "extra == 'realtime'", specifier = ">=0.7.0" },
{ name = "crewai", marker = "extra == 'autogen'" },
{ name = "crewai", marker = "extra == 'autogen-v4'" },
{ name = "crewai", marker = "extra == 'crewai'", specifier = ">=0.148.0" },
{ name = "crewai", marker = "extra == 'crewai'", specifier = ">=0.157.0" },
{ name = "duckduckgo-search", marker = "extra == 'realtime'", specifier = ">=6.3.0" },
{ name = "fastapi", marker = "extra == 'api'", specifier = ">=0.115.0" },
{ name = "fastapi", marker = "extra == 'call'", specifier = ">=0.95.0" },
@@ -4185,7 +4197,7 @@ requires-dist = [
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.22" },
{ name = "praisonai-tools", marker = "extra == 'autogen-v4'", specifier = ">=0.0.22" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.22" },
{ name = "praisonaiagents", specifier = ">=0.0.160" },
{ name = "praisonaiagents", specifier = ">=0.0.168" },
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = "==0.2.29" },
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
@@ -4240,7 +4252,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.160"
version = "0.0.168"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -4249,9 +4261,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/07/e7/9024fdd48cebd4de622322f81e1f0bf78b70d5e196c607d53d3a0188c198/praisonaiagents-0.0.160.tar.gz", hash = "sha256:dbd116857d65f873369c2b2ec7bec86772cc74aadfb276d73b4b349b88e6902f", size = 285781, upload-time = "2025-08-08T11:17:46.692Z" }
sdist = { url = "https://files.pythonhosted.org/packages/71/a9/d4e0effb144fefe14d724dea9765cf27935d6bd9cd1c76b80ac8961d2f86/praisonaiagents-0.0.168.tar.gz", hash = "sha256:744156db568d595004d8b29a72a214dbad6a9a4702b6f72eff8f08aba77515b1", size = 304818, upload-time = "2025-12-15T08:10:54.72Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/67/a6/f6f0ca75ec5f7fb2a5ce97cfb1c7e25398e77e542a64a3100ba45da74e5a/praisonaiagents-0.0.160-py3-none-any.whl", hash = "sha256:5ba5b902057a39f4f5070a701ae5cb1d306fd1f75def10052953b64edde99c6b", size = 305085, upload-time = "2025-08-08T11:17:45.323Z" },
{ url = "https://files.pythonhosted.org/packages/7b/42/3077b1892c3ec0cce059a17dd8517e8f7b4b7944115e3d6025eeb91f633c/praisonaiagents-0.0.168-py3-none-any.whl", hash = "sha256:3e7095da3ebbe1d7c23613418b3200f3d42198ae2ccde08dd753cf548a549e93", size = 322039, upload-time = "2025-12-15T08:10:53.526Z" },
]
[[package]]