Compare commits

...
72 Commits
Author SHA1 Message Date
Mervin Praison 657fd93743 Release v3.9.2 2026-01-16 04:37:53 +00:00
github-actions[bot] f0a2936b7f docs: auto-update api.md [skip ci] 2026-01-15 20:08:49 +00:00
Mervin Praison 58778492ca Release v3.9.1 2026-01-15 20:08:35 +00:00
Mervin Praison 08c444f3a8 Release v3.9.0 2026-01-15 16:05:47 +00:00
Mervin Praison 34c1b39e95 Release v3.8.22 2026-01-15 13:01:10 +00:00
Mervin Praison 5e4c58a9ac fix(ci): correct CLI commands - session list, queue list (not ls) 2026-01-15 11:06:32 +00:00
Mervin Praison 19a30ff3d9 fix(ci): fix Handoff test - use correct parameters 2026-01-15 11:00:32 +00:00
Mervin Praison 50f12c7682 fix(ci): correct PlanningConfig params (reasoning, auto_approve) 2026-01-15 10:57:50 +00:00
Mervin Praison 5a70b8abb9 fix(ci): correct ExecutionConfig params (max_iter, max_retry_limit) 2026-01-15 10:55:33 +00:00
Mervin Praison b7d4d219b9 fix(ci): correct MemoryConfig test to use backend param 2026-01-15 10:52:56 +00:00
Mervin Praison ff2d83ffdf Release v3.8.21 2026-01-15 10:50:27 +00:00
Mervin Praison 2d58caa741 fix(ci): correct import paths for Windows tests
- MemoryConfig from praisonaiagents.config (not memory)
- FileMemory from praisonaiagents.memory
- OutputConfig, ExecutionConfig, PlanningConfig from config
2026-01-15 10:50:25 +00:00
Mervin Praison d31cf379e5 feat(ci): expand Windows tests with Memory, Tools, Config, Handoff, async
Added tests for:
- Memory: FileMemory, MemoryConfig
- Tool decorator (@tool)
- Config classes: OutputConfig, ExecutionConfig, PlanningConfig
- Handoff between agents
- Async features (arun, astart availability)
- Multi-agent real API test
2026-01-15 10:47:11 +00:00
Mervin Praison 719ef04e7c fix(memory): make fcntl import conditional for Windows compatibility
fcntl is Unix-only; on Windows, skip file locking.
This fixes ModuleNotFoundError: No module named 'fcntl' on Windows.

- Add _HAS_FCNTL flag based on sys.platform
- Update _read_json and _write_json to conditionally use fcntl.flock
- File locking is acceptable to skip for single-process usage
2026-01-15 10:38:45 +00:00
Mervin Praison 4fb25a99d5 fix(ci): fix Windows workflow YAML syntax and secrets condition 2026-01-15 10:35:18 +00:00
Mervin Praison 0fdacff2cf feat(ci): add Windows CI test workflow
Tests key PraisonAI functionality on Windows:
- Core imports: Agent, Agents, Workflow, Task, WorkflowStep
- Object instantiation
- CLI commands: --help, session ls, queue ls
- Real API test with OPENAI_API_KEY

Timeout: 5 minutes
Runs on: windows-latest
Triggers: push/PR to main/develop + manual dispatch
2026-01-15 10:33:56 +00:00
Mervin Praison 6a1fa19c6e Release v3.8.20 2026-01-15 09:45:45 +00:00
Mervin Praison a4725a027a Release v3.8.19 2026-01-15 07:29:27 +00:00
Mervin Praison dc9a8f3443 Release v3.8.18 2026-01-15 04:41:16 +00:00
Mervin Praison 9421e28c8a Release v3.8.17 2026-01-13 18:29:06 +00:00
Mervin Praison c3d60c82ca feat: add debug output with token/cost metrics
- Added llm_end callback to openai_client.py and llm.py with:
  - tokens_in, tokens_out from usage
  - cost from litellm.completion_cost()
  - latency_ms timing
- Updated trace.py and status.py to display metrics
- Added show_metrics param to enable debug mode metrics display
- Agent.py passes metrics flag to enable_status_output

Debug output now shows:
  [17:18:22] Calling LLM (gpt-4o-mini)...
  [17:18:24]   │ 📊 gpt-4o-mini: 104→14 tokens [1.5s]
  [17:18:24] ▸ get_weather(city='Tokyo')
  [17:18:24] Calling LLM (gpt-4o-mini)...
  [17:18:25]   │ 📊 gpt-4o-mini: 133→8 tokens [0.7s]
  Response: The weather in Tokyo is sunny.
2026-01-13 17:20:06 +00:00
Mervin Praison 8c509b439f Release v3.8.16 2026-01-13 16:55:40 +00:00
Mervin Praison 3fbf1a353e fix: consistent status output for all LLM paths (OpenAI + LiteLLM)
- Fixed _execute_callback_and_display to always trigger callback
  (removed incorrect 'if not _using_custom_llm' guard)
- Added tool_call callback to llm.py for LiteLLM path
- Removed duplicate llm_start callback from llm.py method entry
- Reset AI call counter between agent runs
- Both sync LLM paths now show identical output

Verified output for both paths:
  ▸ AI → thinking...
    │ → get_weather(city="Tokyo") → sunny
  ▸ AI → responding...
  Final Output: ...
2026-01-13 16:45:08 +00:00
Mervin Praison e0f3a49e41 improve: status output UX - cleaner, user-friendly format
- Changed 'LLM' to 'AI' for user-friendliness
- Added context: 'thinking' (1st call) / 'responding' (2nd call)
- Tool calls now show inline with result: │ → tool(args) → result
- Fixed openai_client to pass structured params to callbacks

Output now looks like:
  ▸ AI → thinking...
    │ → get_weather(city="Tokyo") → sunny
  ▸ AI → responding...
  Final Output: ...
2026-01-13 16:36:51 +00:00
Mervin Praison 987b43877f fix: show all LLM calls in status output (including tool follow-ups)
- Added llm_start callback in openai_client.py while loop
- Each LLM API call now triggers callback for status display
- Removed duplicate callback from agent._chat_completion

Status output now correctly shows:
  ▸ Calling LLM (gpt-4o-mini)...       # 1st: decides to call tool
  │ → get_weather(city="Tokyo")
  ▸ Calling LLM (gpt-4o-mini)...       # 2nd: generates response
  Final Output: ...
2026-01-13 16:18:53 +00:00
Mervin Praison ebb383208e feat: add LLM call display to status/trace output
- Added llm_start callback in agent._chat_completion()
- Registered on_llm_start callback in enable_status_output()
- StatusOutput.llm_start() displays '▸ Calling LLM (model)...'
- Works for both LiteLLM and OpenAI client paths

Status output now shows:
  ▸ Calling LLM (openai/gpt-4o-mini)...
  │ → get_weather(city="Tokyo")
  Final Output: ...
2026-01-13 16:10:46 +00:00
Mervin Praison c9e4f0738a refactor: rename output modules for user-friendliness
- Rename actions.py → status.py (handles status preset, no timestamps)
- Rename old status.py → trace.py (handles trace preset, with timestamps)
- ActionsSink → StatusOutput
- StatusSink → TraceOutput
- enable_actions_mode → enable_status_output
- enable_status_mode → enable_trace_output

This makes internal code match user-facing preset names:
  output='status' → StatusOutput (▸ tool → result)
  output='trace' → TraceOutput ([HH:MM:SS] ▸ tool [0.2s])
2026-01-13 15:59:42 +00:00
Mervin Praison db0a24555d fix: status preset correctly hides timestamps, add LLM call methods
- Added show_timestamps param to ActionsSink (default True)
- Agent passes show_timestamps=False for status preset (simple_output=True)
- Added llm_start/llm_end methods to ActionsSink for future LLM tracking
- status: │ → tool() (no timestamps)
- trace: [HH:MM:SS] ▸ tool [0.2s] ✓ (with timestamps)
2026-01-13 15:51:51 +00:00
Mervin Praison e3fe35e2b6 fix: status preset now hides timestamps correctly
- Added show_timestamps param to ActionsSink
- Agent passes show_timestamps=False when simple_output=True
- status: │ → tool() (no timestamps)
- trace: [HH:MM:SS] ▸ tool [0.2s] ✓ (with timestamps)
2026-01-13 15:46:57 +00:00
Mervin Praison 74a7322b83 refactor: rename output presets for clarity
- Rename 'text' → 'status' (no timestamps, simple progress)
- Rename old 'status' → 'trace' (with timestamps, full trace)
- Change 'debug' = trace + metrics (no boxes, developer-focused)
- Keep 'verbose' = rich panels (interactive use)
- Add 'text' as backward compat alias → status

New hierarchy (most intuitive):
  silent → status → trace → debug → verbose → stream → json
2026-01-13 15:10:05 +00:00
Mervin Praison 7ceb7f8cb9 Release v3.8.14 2026-01-13 14:46:59 +00:00
Mervin Praison 84e5b6c693 fix: Agents panels now render Markdown (bold, headers, lists)
Changed Text() to Markdown() in agents.start() verbose output so
**bold**, # headers, - lists render properly in multi-agent panels.
2026-01-13 14:44:17 +00:00
Mervin Praison 5f00ddbc7c Release v3.8.13 2026-01-13 14:43:54 +00:00
Mervin Praison db551c5d65 feat: add Markdown rendering for status output mode
- Added use_markdown=True parameter to StatusSink
- response() now renders content with rich.markdown.Markdown
- Lazy import for performance, graceful fallback
2026-01-13 14:39:53 +00:00
Mervin Praison aed6027256 Release v3.8.12 2026-01-13 14:33:31 +00:00
Mervin Praison a9d709645a fix: respect explicit output config, don't override with TTY auto-verbose
- Added _has_explicit_output_config flag to track when user sets output=
- Modified agent.start() to skip TTY auto-verbose if user explicitly configured output
- Fixes issue where output='status' was overridden by TTY auto-verbose showing panels

Before: output='status' in TTY showed panels (wrong)
After: output='status' in TTY shows clean inline status (correct)
2026-01-13 14:30:56 +00:00
Mervin Praison a430e1b873 Release v3.8.11 2026-01-13 14:21:02 +00:00
Mervin Praison 8e0a40db56 Release v3.8.10 2026-01-13 13:55:31 +00:00
Mervin Praison 8d1e4637d4 feat: add status output mode for clean inline progress
- Add new 'status' preset showing [HH:MM:SS] ▸ tool → result ✓
- Create output/status.py with StatusSink class
- Add status_trace field to OutputConfig
- Update presets.py with full preset hierarchy
- Consolidate presets: text, status, verbose, debug, stream, json
- Add backward compatible aliases (plain→silent, minimal→silent, etc.)

Fixes confusing verbose output by providing clean alternative
2026-01-13 13:52:05 +00:00
Mervin Praison e11d62dc89 Release v3.8.9 2026-01-13 13:14:04 +00:00
Mervin Praison 13a9a3e07d Release v3.8.8 2026-01-13 13:06:26 +00:00
Mervin Praison b95f6b0665 Release v3.8.7 2026-01-13 12:55:43 +00:00
github-actions[bot] e8c4410014 docs: auto-update api.md [skip ci] 2026-01-13 09:30:27 +00:00
Mervin Praison 6c2d852ed1 Release v3.8.6 2026-01-13 09:30:11 +00:00
Mervin Praison 6f95ae8d9d Release v3.8.5 2026-01-13 07:04:53 +00:00
Mervin Praison 8e2dd09b3b Release v3.8.4 2026-01-13 06:17:09 +00:00
github-actions[bot] 8ecfad5c5a docs: auto-update api.md [skip ci] 2026-01-13 06:01:35 +00:00
Mervin Praison 35a88a0913 Release v3.8.3 2026-01-13 06:01:20 +00:00
Mervin Praison 6df3e32640 Release v3.8.2 2026-01-13 04:16:08 +00:00
github-actions[bot] fb36e1c50c docs: auto-update api.md [skip ci] 2026-01-12 17:00:39 +00:00
Mervin Praison ac5454cb00 Release v3.8.1 2026-01-12 17:00:20 +00:00
github-actions[bot] bbe95795d1 docs: auto-update api.md [skip ci] 2026-01-12 12:49:30 +00:00
Mervin Praison bdaf5340f9 Release v3.8.0 2026-01-12 12:49:16 +00:00
Mervin Praison 5579614001 Release v3.7.9 2026-01-12 09:10:46 +00:00
Mervin Praison 2c4dd0e2d4 Release v3.7.8 2026-01-12 07:39:39 +00:00
Mervin Praison fd23d62841 Release v3.7.7 2026-01-11 21:30:04 +00:00
Mervin Praison 5f3bcb78ac Release v3.7.6 2026-01-11 08:23:08 +00:00
Mervin Praison 3c40c2278e Release v3.7.5 2026-01-11 07:34:59 +00:00
Mervin Praison 1921b03aab chore: remove empty trace and comparison test files 2026-01-10 21:09:11 +00:00
Mervin Praison f33bf57662 Release v3.7.4 2026-01-10 21:06:16 +00:00
github-actions[bot] df21c419ea docs: auto-update api.md [skip ci] 2026-01-10 19:45:30 +00:00
Mervin Praison fe997d525c ci: add workflow to auto-update api.md on main branch push 2026-01-10 19:45:04 +00:00
Mervin Praison ca26988774 Release v3.7.3 2026-01-10 19:43:43 +00:00
Mervin Praison 3600594316 Before AI example generation 2026-01-10 16:54:16 +00:00
Mervin Praison 097cd42890 Before testing 2026-01-10 16:04:21 +00:00
Mervin Praison 595add2991 Before testing AI generation 2026-01-10 15:55:26 +00:00
Mervin Praison 03a3aa420b Release v3.7.2 2026-01-10 15:31:05 +00:00
Mervin Praison 9533abd8a4 Release v3.7.1 2026-01-10 14:29:43 +00:00
Mervin Praison 39c9e50875 Release v3.7.0 2026-01-10 13:09:09 +00:00
Mervin Praison 585b68d02c Release v3.6.2 2026-01-10 09:08:53 +00:00
Mervin Praison 66481cc51c Release v3.6.1 2026-01-09 17:16:27 +00:00
Mervin Praison 8e637daecd Release v3.6.0 2026-01-09 15:45:57 +00:00
475 changed files with 51241 additions and 7771 deletions

No files matched your search

+204
View File
@@ -0,0 +1,204 @@
name: Windows Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
workflow_dispatch:
jobs:
test-windows:
runs-on: windows-latest
timeout-minutes: 5
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_MODEL_NAME: gpt-4o-mini
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install praisonaiagents
run: |
python -m pip install --upgrade pip
cd src/praisonai-agents
pip install .
shell: bash
- name: Install praisonai wrapper
run: |
cd src/praisonai
pip install .[dev]
shell: bash
# ==================== CORE IMPORTS ====================
- name: Test core imports
run: |
python -c "from praisonaiagents import Agent, Agents, Workflow; print('Core imports OK')"
python -c "from praisonaiagents import tool, Tools; print('Tool imports OK')"
python -c "from praisonaiagents import Task, WorkflowStep; print('Task/Step imports OK')"
# ==================== AGENT FEATURES ====================
- name: Test Agent instantiation
run: |
python -c "
from praisonaiagents import Agent
a = Agent(name='Test', instructions='You are helpful')
print('Agent created:', a.name)
a2 = Agent(name='ToolAgent', instructions='Use tools', tools=[])
print('Agent with tools:', a2.name)
"
- name: Test Agents orchestration
run: |
python -c "
from praisonaiagents import Agent, Agents, Task
a1 = Agent(name='Agent1', instructions='First agent')
a2 = Agent(name='Agent2', instructions='Second agent')
t = Task(description='Do something', agent=a1)
agents = Agents(agents=[a1, a2], tasks=[t])
print('Agents:', len(agents.agents), 'Tasks:', len(agents.tasks))
"
# ==================== WORKFLOW FEATURES ====================
- name: Test Workflow and WorkflowStep
run: |
python -c "
from praisonaiagents import Workflow, WorkflowStep
from praisonaiagents.workflows import WorkflowOutputConfig
w = Workflow(name='test')
s1 = WorkflowStep(name='step1')
s2 = WorkflowStep(name='step2', context=['step1'])
print('Workflow:', w.name)
print('Steps:', s1.name, s2.name)
cfg = WorkflowOutputConfig(verbose=True, stream=False)
w2 = Workflow(name='configured', output=cfg)
print('Configured workflow verbose:', w2.verbose)
"
# ==================== MEMORY FEATURES ====================
- name: Test Memory classes
run: |
python -c "
from praisonaiagents.memory import FileMemory
from praisonaiagents.config import MemoryConfig
cfg = MemoryConfig(backend='file', user_id='test_user')
print('MemoryConfig backend:', cfg.backend)
mem = FileMemory(user_id='test_user', base_path='.praison/test_memory')
print('FileMemory user:', mem.user_id)
"
# ==================== TOOL DECORATOR ====================
- name: Test tool decorator
run: |
python -c "
from praisonaiagents import tool
@tool
def my_tool(query: str) -> str:
'''A test tool'''
return f'Echo: {query}'
result = my_tool('hello')
print('Tool result:', result)
"
# ==================== CONFIG CLASSES ====================
- name: Test config classes
run: |
python -c "
from praisonaiagents.config import OutputConfig, ExecutionConfig, PlanningConfig
out_cfg = OutputConfig(verbose=True, stream=True)
print('OutputConfig verbose:', out_cfg.verbose)
exec_cfg = ExecutionConfig(max_iter=50, max_retry_limit=5)
print('ExecutionConfig max_iter:', exec_cfg.max_iter)
plan_cfg = PlanningConfig(reasoning=True, auto_approve=False)
print('PlanningConfig reasoning:', plan_cfg.reasoning)
"
# ==================== HANDOFF ====================
- name: Test Handoff
run: |
python -c "
from praisonaiagents import Handoff, handoff, Agent
a1 = Agent(name='Agent1', instructions='First')
a2 = Agent(name='Agent2', instructions='Second')
# Using Handoff class directly
h = Handoff(agent=a2)
print('Handoff tool name:', h.tool_name)
# Using handoff function
h2 = handoff(a1, tool_name_override='custom_handoff')
print('Custom handoff name:', h2.tool_name)
"
# ==================== ASYNC FEATURES ====================
- name: Test async imports
run: |
python -c "
import asyncio
from praisonaiagents import Agent
async def test_async():
agent = Agent(name='AsyncAgent', instructions='Test')
assert hasattr(agent, 'arun'), 'Missing arun'
assert hasattr(agent, 'astart'), 'Missing astart'
print('Async methods available')
asyncio.run(test_async())
"
# ==================== CLI COMMANDS ====================
- name: Test CLI help
run: praisonai --help
- name: Test CLI session list
run: praisonai session list
continue-on-error: true
- name: Test CLI queue list
run: praisonai queue list
continue-on-error: true
# ==================== REAL API TESTS ====================
- name: Real API test - Agent run
if: env.OPENAI_API_KEY != ''
run: |
python -c "
from praisonaiagents import Agent
agent = Agent(name='TestAgent', instructions='Reply with exactly: WINDOWS_OK', llm='gpt-4o-mini')
result = agent.run('Say WINDOWS_OK')
print('Result:', result)
print('Real API test passed')
"
- name: Real API test - Multi-agent
if: env.OPENAI_API_KEY != ''
run: |
python -c "
from praisonaiagents import Agent, Agents, Task
researcher = Agent(name='Researcher', instructions='You research topics', llm='gpt-4o-mini')
writer = Agent(name='Writer', instructions='You write content', llm='gpt-4o-mini')
task = Task(description='Say hello world', agent=researcher)
agents = Agents(agents=[researcher, writer], tasks=[task])
result = agents.start()
print('Multi-agent result type:', type(result))
print('Multi-agent test passed')
"
+57
View File
@@ -0,0 +1,57 @@
name: Update API Reference
on:
push:
branches: [ "main" ]
paths:
- 'src/praisonai-agents/praisonaiagents/**/*.py'
- 'src/praisonai/praisonai/**/*.py'
- 'src/praisonai-ts/src/**/*.ts'
- '.github/workflows/update-api-md.yml'
permissions:
contents: write
jobs:
update-api-md:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: main
persist-credentials: true
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Generate api.md
run: |
cd $GITHUB_WORKSPACE
python3 src/praisonai/scripts/generate_api_md.py
- name: Check for changes
id: check_changes
run: |
if git diff --quiet api.md; then
echo "changes=false" >> $GITHUB_OUTPUT
echo "No changes to api.md"
else
echo "changes=true" >> $GITHUB_OUTPUT
echo "api.md has been updated"
git diff api.md | head -50
fi
- name: Commit and push changes
if: steps.check_changes.outputs.changes == 'true'
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "docs: auto-update api.md [skip ci]"
file_pattern: 'api.md'
commit_user_name: "github-actions[bot]"
commit_user_email: "41898282+github-actions[bot]@users.noreply.github.com"
commit_author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
+2 -1
View File
@@ -83,4 +83,5 @@ issue_details.json
# MCP Registry tokens
.mcpregistry_*
*.log
*.log
.internal
+1 -1
View File
@@ -23,7 +23,7 @@
</div>
PraisonAI is a production-ready Multi-AI Agents framework with self-reflection, designed to create AI Agents to automate and solve problems ranging from simple tasks to complex challenges. By integrating PraisonAI Agents, AG2 (Formerly AutoGen), and CrewAI into a low-code solution, it streamlines the building and management of multi-agent LLM systems, emphasising simplicity, customisation, and effective human-agent collaboration.
PraisonAI is a production-ready Multi-AI Agents framework with self-reflection, designed to create AI Agents to automate and solve problems ranging from simple tasks to complex challenges. It provides a low-code solution to streamline the building and management of multi-agent LLM systems, emphasising simplicity, customisation, and effective human-agent collaboration.
<div align="center">
<a href="https://docs.praison.ai">
+441
View File
@@ -0,0 +1,441 @@
# PraisonAI API Reference
This file is auto-generated. Do not edit manually.
Regenerate with: `praisonai docs api-md --write`
# Agents
Types:
```python
from praisonaiagents import Agent, Agents
```
Methods:
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">achat</a>(prompt: str, temperature = 1.0, tools = None, output_json = None, output_pydantic = None, reasoning_steps = False, task_name = None, task_description = None, task_id = None)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">aexecute</a>(task, context = None)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">agent_id</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">analyze_prompt</a>(prompt: str) -> set</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">arun</a>(prompt: str, **kwargs)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">astart</a>(prompt: str, **kwargs)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">auto_memory</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">auto_memory</a>(value)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">background</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">background</a>(value)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">chat</a>(prompt, temperature = 1.0, tools = None, output_json = None, output_pydantic = None, reasoning_steps = False, stream = None, task_name = None, task_description = None, task_id = None, config = None, force_retrieval = False, skip_retrieval = False)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">chat_with_context</a>(message: str, context: 'ContextPack', **kwargs) -> str</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">checkpoints</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">checkpoints</a>(value)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">clean_json_output</a>(output: str) -> str</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">clear_history</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">console</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">context_manager</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">context_manager</a>(value)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">display_generating</a>(content: str, start_time: float)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">execute</a>(task, context = None)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">execute_tool</a>(function_name, arguments)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">execute_tool_async</a>(function_name: str, arguments: Dict[str, Any]) -> Any</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">from_template</a>(uri: str, config: Optional[Dict[str, Any]] = None, offline: bool = False, **kwargs) -> 'Agent'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">generate_task</a>() -> 'Task'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">get_available_tools</a>() -> List[Any]</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">get_memory_context</a>(query: Optional[str] = None) -> str</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">get_recommended_stage</a>(prompt: str) -> str</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">get_rules_context</a>(file_path: Optional[str] = None, include_manual: Optional[List[str]] = None) -> str</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">get_skills_prompt</a>() -> str</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">handoff_to</a>(target_agent: 'Agent', prompt: str, context: Optional[Dict[str, Any]] = None, config: Optional['HandoffConfig'] = None) -> 'HandoffResult'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">handoff_to_async</a>(target_agent: 'Agent', prompt: str, context: Optional[Dict[str, Any]] = None, config: Optional['HandoffConfig'] = None) -> 'HandoffResult'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">iter_stream</a>(prompt: str, **kwargs)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">launch</a>(path: str = '/', port: int = 8000, host: str = '0.0.0.0', debug: bool = False, protocol: str = 'http')</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">llm_model</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">output_style</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">output_style</a>(value)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">policy</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">policy</a>(value)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">query</a>(question: str, **kwargs) -> 'RAGResult'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">rag</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">rag_query</a>(question: str, **kwargs) -> 'RAGResult'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">retrieval_config</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">retrieve</a>(query: str, **kwargs) -> 'ContextPack'</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">rules_manager</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run</a>(prompt: str, **kwargs)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run_autonomous</a>(prompt: str, max_iterations: Optional[int] = None, timeout_seconds: Optional[float] = None)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">session_id</a>() -> Optional[str]</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">skill_manager</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">start</a>(prompt: str = None, **kwargs)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">store_memory</a>(content: str, memory_type: str = 'short_term', **kwargs)</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">switch_model</a>(new_model: str) -> None</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">thinking_budget</a>()</code>
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">thinking_budget</a>(value)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">add_task</a>(task)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">aexecute_task</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">append_to_state</a>(key: str, value: Any, max_length: Optional[int] = None) -> List[Any]</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">arun_all_tasks</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">arun_task</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">astart</a>(content = None, return_dict = False, **kwargs)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">clean_json_output</a>(output: str) -> str</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">clear_state</a>() -> None</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">context_manager</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">current_plan</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">default_completion_checker</a>(task, agent_output)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">delete_state</a>(key: str) -> bool</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">display_token_usage</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">execute_task</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_agent_details</a>(agent_name)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_all_state</a>() -> Dict[str, Any]</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_all_tasks_status</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_detailed_token_report</a>() -> Dict[str, Any]</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_plan_markdown</a>() -> str</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_state</a>(key: str, default: Any = None) -> Any</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_task_details</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_task_result</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_task_status</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_todo_markdown</a>() -> str</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_token_usage_summary</a>() -> Dict[str, Any]</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">has_state</a>(key: str) -> bool</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">increment_state</a>(key: str, amount: float = 1, default: float = 0) -> float</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">launch</a>(path: str = '/agents', port: int = 8000, host: str = '0.0.0.0', debug: bool = False, protocol: str = 'http')</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">restore_session_state</a>(session_id: str) -> bool</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">run</a>(content = None, return_dict = False, **kwargs)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">run_all_tasks</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">run_task</a>(task_id)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">save_output_to_file</a>(task, task_output)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">save_session_state</a>(session_id: str, include_memory: bool = True) -> None</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">set_state</a>(key: str, value: Any) -> None</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">start</a>(content = None, return_dict = False, output = None, **kwargs)</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">todo_list</a>()</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">update_plan_step_status</a>(step_id: str, status: str) -> bool</code>
* <code title="class Agents">Agents.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">update_state</a>(updates: Dict) -> None</code>
# Tools
Types:
```python
from praisonaiagents import Tools, tool
```
Methods:
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/tools/decorator.py">tool</a>(func: Optional[Callable] = None) -> Union[FunctionTool, Callable[[Callable], FunctionTool]]</code>
# Other
Types:
```python
from praisonaiagents import Task
```
Methods:
* <code title="class Task">Task.<a href="./src/praisonai-agents/praisonaiagents/task/task.py">execute_callback</a>(task_output: TaskOutput) -> None</code>
* <code title="class Task">Task.<a href="./src/praisonai-agents/praisonaiagents/task/task.py">execute_callback_sync</a>(task_output: TaskOutput) -> None</code>
* <code title="class Task">Task.<a href="./src/praisonai-agents/praisonaiagents/task/task.py">initialize_memory</a>()</code>
* <code title="class Task">Task.<a href="./src/praisonai-agents/praisonaiagents/task/task.py">store_in_memory</a>(content: str, agent_name: str = None, task_id: str = None)</code>
# Wrapper (praisonai)
Types:
```python
from praisonai import CloudProvider, Deploy, DeployConfig, DeployType, PraisonAI, __version__
```
# CLI
Methods:
* <code title="cli">praisonai <a href="./src/praisonai/praisonai/cli/main.py">--help</a></code>
* <code title="cli">praisonai acp acp-main <a href="./src/praisonai/praisonai/cli/commands/acp.py">--help</a></code>
* <code title="cli">praisonai agents create <a href="./src/praisonai/praisonai/cli/commands/agents.py">--help</a></code>
* <code title="cli">praisonai agents info <a href="./src/praisonai/praisonai/cli/commands/agents.py">--help</a></code>
* <code title="cli">praisonai agents list <a href="./src/praisonai/praisonai/cli/commands/agents.py">--help</a></code>
* <code title="cli">praisonai audit agent-centric <a href="./src/praisonai/praisonai/cli/commands/audit.py">--help</a></code>
* <code title="cli">praisonai benchmark agent <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark benchmark-callback <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark cli <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark compare <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark litellm <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark profile <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark sdk <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai benchmark workflow <a href="./src/praisonai/praisonai/cli/commands/benchmark.py">--help</a></code>
* <code title="cli">praisonai call call-main <a href="./src/praisonai/praisonai/cli/commands/call.py">--help</a></code>
* <code title="cli">praisonai chat <a href="./src/praisonai/praisonai/cli/main.py">--help</a></code>
* <code title="cli">praisonai chat chat-main <a href="./src/praisonai/praisonai/cli/commands/chat.py">--help</a></code>
* <code title="cli">praisonai code <a href="./src/praisonai/praisonai/cli/main.py">--help</a></code>
* <code title="cli">praisonai code code-main <a href="./src/praisonai/praisonai/cli/commands/code.py">--help</a></code>
* <code title="cli">praisonai commit commit-main <a href="./src/praisonai/praisonai/cli/commands/commit.py">--help</a></code>
* <code title="cli">praisonai completion bash <a href="./src/praisonai/praisonai/cli/commands/completion.py">--help</a></code>
* <code title="cli">praisonai completion completion-callback <a href="./src/praisonai/praisonai/cli/commands/completion.py">--help</a></code>
* <code title="cli">praisonai completion fish <a href="./src/praisonai/praisonai/cli/commands/completion.py">--help</a></code>
* <code title="cli">praisonai completion zsh <a href="./src/praisonai/praisonai/cli/commands/completion.py">--help</a></code>
* <code title="cli">praisonai config get <a href="./src/praisonai/praisonai/cli/commands/config.py">--help</a></code>
* <code title="cli">praisonai config list <a href="./src/praisonai/praisonai/cli/commands/config.py">--help</a></code>
* <code title="cli">praisonai config path <a href="./src/praisonai/praisonai/cli/commands/config.py">--help</a></code>
* <code title="cli">praisonai config reset <a href="./src/praisonai/praisonai/cli/commands/config.py">--help</a></code>
* <code title="cli">praisonai config set <a href="./src/praisonai/praisonai/cli/commands/config.py">--help</a></code>
* <code title="cli">praisonai context add <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context clear <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context compact <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context export <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context grep <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context list <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context show <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context stats <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai context tail <a href="./src/praisonai/praisonai/cli/commands/context.py">--help</a></code>
* <code title="cli">praisonai debug acp <a href="./src/praisonai/praisonai/cli/commands/debug.py">--help</a></code>
* <code title="cli">praisonai debug debug-callback <a href="./src/praisonai/praisonai/cli/commands/debug.py">--help</a></code>
* <code title="cli">praisonai debug interactive <a href="./src/praisonai/praisonai/cli/commands/debug.py">--help</a></code>
* <code title="cli">praisonai debug lsp <a href="./src/praisonai/praisonai/cli/commands/debug.py">--help</a></code>
* <code title="cli">praisonai debug trace <a href="./src/praisonai/praisonai/cli/commands/debug.py">--help</a></code>
* <code title="cli">praisonai deploy aws <a href="./src/praisonai/praisonai/cli/commands/deploy.py">--help</a></code>
* <code title="cli">praisonai deploy azure <a href="./src/praisonai/praisonai/cli/commands/deploy.py">--help</a></code>
* <code title="cli">praisonai deploy docker <a href="./src/praisonai/praisonai/cli/commands/deploy.py">--help</a></code>
* <code title="cli">praisonai deploy gcp <a href="./src/praisonai/praisonai/cli/commands/deploy.py">--help</a></code>
* <code title="cli">praisonai diag diag-callback <a href="./src/praisonai/praisonai/cli/commands/diag.py">--help</a></code>
* <code title="cli">praisonai diag export <a href="./src/praisonai/praisonai/cli/commands/diag.py">--help</a></code>
* <code title="cli">praisonai docs api-md <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs generate <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs list <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs report <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs run <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs run-all <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs serve <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai docs stats <a href="./src/praisonai/praisonai/cli/commands/docs.py">--help</a></code>
* <code title="cli">praisonai doctor cleanup <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor config <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor db <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor doctor-callback <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor env <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor mcp <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor network <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor performance <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor selftest <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor tools <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai doctor troubleshoot <a href="./src/praisonai/praisonai/cli/commands/doctor.py">--help</a></code>
* <code title="cli">praisonai endpoints list <a href="./src/praisonai/praisonai/cli/commands/endpoints.py">--help</a></code>
* <code title="cli">praisonai endpoints test <a href="./src/praisonai/praisonai/cli/commands/endpoints.py">--help</a></code>
* <code title="cli">praisonai environment check <a href="./src/praisonai/praisonai/cli/commands/environment.py">--help</a></code>
* <code title="cli">praisonai environment doctor <a href="./src/praisonai/praisonai/cli/commands/environment.py">--help</a></code>
* <code title="cli">praisonai environment view <a href="./src/praisonai/praisonai/cli/commands/environment.py">--help</a></code>
* <code title="cli">praisonai eval accuracy <a href="./src/praisonai/praisonai/cli/commands/eval.py">--help</a></code>
* <code title="cli">praisonai eval performance <a href="./src/praisonai/praisonai/cli/commands/eval.py">--help</a></code>
* <code title="cli">praisonai examples info <a href="./src/praisonai/praisonai/cli/commands/examples.py">--help</a></code>
* <code title="cli">praisonai examples list <a href="./src/praisonai/praisonai/cli/commands/examples.py">--help</a></code>
* <code title="cli">praisonai examples report <a href="./src/praisonai/praisonai/cli/commands/examples.py">--help</a></code>
* <code title="cli">praisonai examples run <a href="./src/praisonai/praisonai/cli/commands/examples.py">--help</a></code>
* <code title="cli">praisonai examples run-all <a href="./src/praisonai/praisonai/cli/commands/examples.py">--help</a></code>
* <code title="cli">praisonai examples stats <a href="./src/praisonai/praisonai/cli/commands/examples.py">--help</a></code>
* <code title="cli">praisonai hooks add <a href="./src/praisonai/praisonai/cli/commands/hooks.py">--help</a></code>
* <code title="cli">praisonai hooks list <a href="./src/praisonai/praisonai/cli/commands/hooks.py">--help</a></code>
* <code title="cli">praisonai hooks remove <a href="./src/praisonai/praisonai/cli/commands/hooks.py">--help</a></code>
* <code title="cli">praisonai knowledge add <a href="./src/praisonai/praisonai/cli/commands/knowledge.py">--help</a></code>
* <code title="cli">praisonai knowledge index <a href="./src/praisonai/praisonai/cli/commands/knowledge.py">--help</a></code>
* <code title="cli">praisonai knowledge list <a href="./src/praisonai/praisonai/cli/commands/knowledge.py">--help</a></code>
* <code title="cli">praisonai knowledge search <a href="./src/praisonai/praisonai/cli/commands/knowledge.py">--help</a></code>
* <code title="cli">praisonai lsp logs <a href="./src/praisonai/praisonai/cli/commands/lsp.py">--help</a></code>
* <code title="cli">praisonai lsp lsp-callback <a href="./src/praisonai/praisonai/cli/commands/lsp.py">--help</a></code>
* <code title="cli">praisonai lsp start <a href="./src/praisonai/praisonai/cli/commands/lsp.py">--help</a></code>
* <code title="cli">praisonai lsp status <a href="./src/praisonai/praisonai/cli/commands/lsp.py">--help</a></code>
* <code title="cli">praisonai lsp stop <a href="./src/praisonai/praisonai/cli/commands/lsp.py">--help</a></code>
* <code title="cli">praisonai mcp add <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp describe <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp list <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp mcp-callback <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp remove <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp run <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp status <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp sync <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp test <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai mcp tools <a href="./src/praisonai/praisonai/cli/commands/mcp.py">--help</a></code>
* <code title="cli">praisonai memory add <a href="./src/praisonai/praisonai/cli/commands/memory.py">--help</a></code>
* <code title="cli">praisonai memory clear <a href="./src/praisonai/praisonai/cli/commands/memory.py">--help</a></code>
* <code title="cli">praisonai memory search <a href="./src/praisonai/praisonai/cli/commands/memory.py">--help</a></code>
* <code title="cli">praisonai memory show <a href="./src/praisonai/praisonai/cli/commands/memory.py">--help</a></code>
* <code title="cli">praisonai memory status <a href="./src/praisonai/praisonai/cli/commands/memory.py">--help</a></code>
* <code title="cli">praisonai package install <a href="./src/praisonai/praisonai/cli/commands/package.py">--help</a></code>
* <code title="cli">praisonai package list <a href="./src/praisonai/praisonai/cli/commands/package.py">--help</a></code>
* <code title="cli">praisonai package uninstall <a href="./src/praisonai/praisonai/cli/commands/package.py">--help</a></code>
* <code title="cli">praisonai profile imports <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai profile optimize <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai profile profile-callback <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai profile query <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai profile snapshot <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai profile startup <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai profile suite <a href="./src/praisonai/praisonai/cli/commands/profile.py">--help</a></code>
* <code title="cli">praisonai rag chat <a href="./src/praisonai/praisonai/cli/commands/rag.py">--help</a></code>
* <code title="cli">praisonai rag eval <a href="./src/praisonai/praisonai/cli/commands/rag.py">--help</a></code>
* <code title="cli">praisonai rag index <a href="./src/praisonai/praisonai/cli/commands/rag.py">--help</a></code>
* <code title="cli">praisonai rag query <a href="./src/praisonai/praisonai/cli/commands/rag.py">--help</a></code>
* <code title="cli">praisonai rag serve <a href="./src/praisonai/praisonai/cli/commands/rag.py">--help</a></code>
* <code title="cli">praisonai realtime realtime-main <a href="./src/praisonai/praisonai/cli/commands/realtime.py">--help</a></code>
* <code title="cli">praisonai recipe install <a href="./src/praisonai/praisonai/cli/commands/recipe.py">--help</a></code>
* <code title="cli">praisonai recipe list <a href="./src/praisonai/praisonai/cli/commands/recipe.py">--help</a></code>
* <code title="cli">praisonai recipe run <a href="./src/praisonai/praisonai/cli/commands/recipe.py">--help</a></code>
* <code title="cli">praisonai registry list <a href="./src/praisonai/praisonai/cli/commands/registry.py">--help</a></code>
* <code title="cli">praisonai registry serve <a href="./src/praisonai/praisonai/cli/commands/registry.py">--help</a></code>
* <code title="cli">praisonai research research-main <a href="./src/praisonai/praisonai/cli/commands/research.py">--help</a></code>
* <code title="cli">praisonai retrieval index <a href="./src/praisonai/praisonai/cli/commands/retrieval.py">--help</a></code>
* <code title="cli">praisonai retrieval query <a href="./src/praisonai/praisonai/cli/commands/retrieval.py">--help</a></code>
* <code title="cli">praisonai retrieval search <a href="./src/praisonai/praisonai/cli/commands/retrieval.py">--help</a></code>
* <code title="cli">praisonai rules add <a href="./src/praisonai/praisonai/cli/commands/rules.py">--help</a></code>
* <code title="cli">praisonai rules clear <a href="./src/praisonai/praisonai/cli/commands/rules.py">--help</a></code>
* <code title="cli">praisonai rules list <a href="./src/praisonai/praisonai/cli/commands/rules.py">--help</a></code>
* <code title="cli">praisonai run <a href="./src/praisonai/praisonai/cli/main.py">--help</a></code>
* <code title="cli">praisonai run run-main <a href="./src/praisonai/praisonai/cli/commands/run.py">--help</a></code>
* <code title="cli">praisonai schedule delete <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule describe <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule list <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule logs <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule restart <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule schedule-callback <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule start <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule stats <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai schedule stop <a href="./src/praisonai/praisonai/cli/commands/schedule.py">--help</a></code>
* <code title="cli">praisonai serve serve-callback <a href="./src/praisonai/praisonai/cli/commands/serve.py">--help</a></code>
* <code title="cli">praisonai serve start <a href="./src/praisonai/praisonai/cli/commands/serve.py">--help</a></code>
* <code title="cli">praisonai serve status <a href="./src/praisonai/praisonai/cli/commands/serve.py">--help</a></code>
* <code title="cli">praisonai serve stop <a href="./src/praisonai/praisonai/cli/commands/serve.py">--help</a></code>
* <code title="cli">praisonai session delete <a href="./src/praisonai/praisonai/cli/commands/session.py">--help</a></code>
* <code title="cli">praisonai session export <a href="./src/praisonai/praisonai/cli/commands/session.py">--help</a></code>
* <code title="cli">praisonai session import <a href="./src/praisonai/praisonai/cli/commands/session.py">--help</a></code>
* <code title="cli">praisonai session list <a href="./src/praisonai/praisonai/cli/commands/session.py">--help</a></code>
* <code title="cli">praisonai session resume <a href="./src/praisonai/praisonai/cli/commands/session.py">--help</a></code>
* <code title="cli">praisonai session show <a href="./src/praisonai/praisonai/cli/commands/session.py">--help</a></code>
* <code title="cli">praisonai skills create <a href="./src/praisonai/praisonai/cli/commands/skills.py">--help</a></code>
* <code title="cli">praisonai skills info <a href="./src/praisonai/praisonai/cli/commands/skills.py">--help</a></code>
* <code title="cli">praisonai skills install <a href="./src/praisonai/praisonai/cli/commands/skills.py">--help</a></code>
* <code title="cli">praisonai skills list <a href="./src/praisonai/praisonai/cli/commands/skills.py">--help</a></code>
* <code title="cli">praisonai skills search <a href="./src/praisonai/praisonai/cli/commands/skills.py">--help</a></code>
* <code title="cli">praisonai skills validate <a href="./src/praisonai/praisonai/cli/commands/skills.py">--help</a></code>
* <code title="cli">praisonai standardise check <a href="./src/praisonai/praisonai/cli/commands/standardise.py">--help</a></code>
* <code title="cli">praisonai standardise fix <a href="./src/praisonai/praisonai/cli/commands/standardise.py">--help</a></code>
* <code title="cli">praisonai standardise init <a href="./src/praisonai/praisonai/cli/commands/standardise.py">--help</a></code>
* <code title="cli">praisonai standardise report <a href="./src/praisonai/praisonai/cli/commands/standardise.py">--help</a></code>
* <code title="cli">praisonai templates create <a href="./src/praisonai/praisonai/cli/commands/templates.py">--help</a></code>
* <code title="cli">praisonai templates list <a href="./src/praisonai/praisonai/cli/commands/templates.py">--help</a></code>
* <code title="cli">praisonai test info <a href="./src/praisonai/praisonai/cli/commands/test.py">--help</a></code>
* <code title="cli">praisonai test interactive <a href="./src/praisonai/praisonai/cli/commands/test.py">--help</a></code>
* <code title="cli">praisonai test run <a href="./src/praisonai/praisonai/cli/commands/test.py">--help</a></code>
* <code title="cli">praisonai todo add <a href="./src/praisonai/praisonai/cli/commands/todo.py">--help</a></code>
* <code title="cli">praisonai todo done <a href="./src/praisonai/praisonai/cli/commands/todo.py">--help</a></code>
* <code title="cli">praisonai todo list <a href="./src/praisonai/praisonai/cli/commands/todo.py">--help</a></code>
* <code title="cli">praisonai tools info <a href="./src/praisonai/praisonai/cli/commands/tools.py">--help</a></code>
* <code title="cli">praisonai tools list <a href="./src/praisonai/praisonai/cli/commands/tools.py">--help</a></code>
* <code title="cli">praisonai tools test <a href="./src/praisonai/praisonai/cli/commands/tools.py">--help</a></code>
* <code title="cli">praisonai traces disable <a href="./src/praisonai/praisonai/cli/commands/traces.py">--help</a></code>
* <code title="cli">praisonai traces enable <a href="./src/praisonai/praisonai/cli/commands/traces.py">--help</a></code>
* <code title="cli">praisonai traces list <a href="./src/praisonai/praisonai/cli/commands/traces.py">--help</a></code>
* <code title="cli">praisonai traces status <a href="./src/praisonai/praisonai/cli/commands/traces.py">--help</a></code>
* <code title="cli">praisonai train train-main <a href="./src/praisonai/praisonai/cli/commands/train.py">--help</a></code>
* <code title="cli">praisonai ui chat <a href="./src/praisonai/praisonai/cli/commands/ui.py">--help</a></code>
* <code title="cli">praisonai ui code <a href="./src/praisonai/praisonai/cli/commands/ui.py">--help</a></code>
* <code title="cli">praisonai ui gradio <a href="./src/praisonai/praisonai/cli/commands/ui.py">--help</a></code>
* <code title="cli">praisonai ui realtime <a href="./src/praisonai/praisonai/cli/commands/ui.py">--help</a></code>
* <code title="cli">praisonai ui ui-main <a href="./src/praisonai/praisonai/cli/commands/ui.py">--help</a></code>
* <code title="cli">praisonai version check <a href="./src/praisonai/praisonai/cli/commands/version.py">--help</a></code>
* <code title="cli">praisonai version show <a href="./src/praisonai/praisonai/cli/commands/version.py">--help</a></code>
* <code title="cli">praisonai version version-callback <a href="./src/praisonai/praisonai/cli/commands/version.py">--help</a></code>
* <code title="cli">praisonai workflow create <a href="./src/praisonai/praisonai/cli/commands/workflow.py">--help</a></code>
* <code title="cli">praisonai workflow list <a href="./src/praisonai/praisonai/cli/commands/workflow.py">--help</a></code>
* <code title="cli">praisonai workflow run <a href="./src/praisonai/praisonai/cli/commands/workflow.py">--help</a></code>
# TypeScript
Types/Exports:
```ts
export { Agent, Agents, PraisonAIAgents, Router } from "./agent";
export type { PraisonAIAgentsConfig, SimpleAgentConfig, SimpleRouteConfig, SimpleRouterConfig } from "./agent";
export { ContextAgent, createContextAgent } from "./agent/context";
export { Handoff, handoff, handoffFilters } from "./agent/handoff";
export { ImageAgent, createImageAgent } from "./agent/image";
export { PromptExpanderAgent, createPromptExpanderAgent } from "./agent/prompt-expander";
export { QueryRewriterAgent, createQueryRewriterAgent } from "./agent/query-rewriter";
export { DeepResearchAgent, createDeepResearchAgent } from "./agent/research";
export { RouterAgent, createRouter, routeConditions } from "./agent/router";
export { // Agent loop
createAgentLoop, // DevTools
enableDevTools, // MCP
createMCP, // Middleware (renamed to avoid conflicts)
createCachingMiddleware, // Models
createModel, // Multimodal
createImagePart, // Next.js
createRouteHandler, // OAuth for MCP
type OAuthClientProvider, // Server adapters
createHttpHandler, // Speech & Transcription
generateSpeech, // Telemetry (AI SDK v6 parity)
configureTelemetry, // Tool Approval (AI SDK v6 parity)
ApprovalManager, // Tools
defineTool, // UI Message (AI SDK v6 parity)
convertToModelMessages, AIAgentStep, AIEmbedManyResult, AIEmbedOptions, AIEmbedResult, AIFilePart, AIGenerateImageOptions, AIGenerateImageResult, AIGenerateObjectOptions, AIGenerateObjectResult, AIGenerateTextOptions, AIGenerateTextResult, AIImagePart, AIMiddleware, AIMiddlewareConfig, AIModelMessage, AISpan, AISpanKind, AISpanOptions, AISpanStatus, AIStreamObjectOptions, AIStreamObjectResult, AIStreamTextOptions, AIStreamTextResult, AITelemetryEvent, AITelemetrySettings, AITextPart, AIToolDefinition, AITracer, AgentLoop, DANGEROUS_PATTERNS, MODEL_ALIASES, SPEECH_MODELS, TRANSCRIPTION_MODELS, ToolApprovalDeniedError, ToolApprovalTimeoutError, aiEmbed, aiEmbedMany, aiGenerateImage, aiGenerateObject, aiGenerateText, aiStreamObject, aiStreamText, applyMiddleware, autoEnableDevTools, base64ToUint8Array, clearAICache, clearEvents, closeAllMCPClients, closeMCPClient, convertToUIMessages, createAILoggingMiddleware, createAISpan, createApprovalResponse, createDangerousPatternChecker, createDevToolsMiddleware, createExpressHandler, createFastifyHandler, createFilePart, createHonoHandler, createMultimodalMessage, createNestHandler, createPagesHandler, createPdfPart, createSystemMessage, createTelemetryMiddleware, createTelemetrySettings, createTextMessage, createTextPart, createToolSet, disableAITelemetry, disableDevTools, enableAITelemetry, functionToTool, getAICacheStats, getApprovalManager, getDevToolsState, getDevToolsUrl, getEvents, getMCPClient, getModel, getTelemetrySettings, getToolsNeedingApproval, getTracer, hasModelAlias, hasPendingApprovals, initOpenTelemetry, isDangerous, isDataUrl, isDevToolsEnabled, isTelemetryEnabled, isUrl, listModelAliases, mcpToolsToAITools, parseModel, pipeUIMessageStreamToResponse, recordEvent, resolveModelAlias, safeValidateUIMessages, setApprovalManager, stopAfterSteps, stopWhen, stopWhenNoToolCalls, toMessageContent, toUIMessageStreamResponse, transcribe, uint8ArrayToBase64, validateUIMessages, withApproval, withSpan, wrapModel } from "./ai";
export { AutoAgents, createAutoAgents } from "./auto";
export { BaseCache, FileCache, MemoryCache, createFileCache, createMemoryCache } from "./cache";
export { CLI_SPEC_VERSION, executeCommand, parseArgs } from "./cli";
export { // Autonomy Mode
AutonomyManager, // Background Jobs
JobQueue, // Checkpoints
CheckpointManager, // Cost Tracker
CostTracker, // External Agents
BaseExternalAgent, // Fast Context
FastContext, // Flow Display
FlowDisplay, // Git Integration
GitManager, // Interactive TUI
InteractiveTUI, // N8N Integration
N8NIntegration, // Repo Map
RepoMap, // Sandbox Executor
SandboxExecutor, // Scheduler
Scheduler, // Slash Commands
SlashCommandHandler, AiderAgent, ClaudeCodeAgent, CodexCliAgent, CommandValidator, CostTokenUsage, DEFAULT_BLOCKED_COMMANDS, DEFAULT_BLOCKED_PATHS, DEFAULT_IGNORE_PATTERNS, DiffViewer, FileCheckpointStorage, FileJobStorage, GeminiCliAgent, GenericExternalAgent, HistoryManager, MODEL_PRICING, MODE_POLICIES, MemoryCheckpointStorage, MemoryJobStorage, StatusDisplay, cliApprovalPrompt, createAutonomyManager, createCheckpointManager, createCostTracker, createDiffViewer, createExternalAgent, createFastContext, createFileCheckpointStorage, createFileJobStorage, createFlowDisplay, createGitManager, createHistoryManager, createInteractiveTUI, createJobQueue, createN8NIntegration, createRepoMap, createSandboxExecutor, createScheduler, createSlashCommandHandler, createStatusDisplay, cronExpressions, estimateTokens, executeSlashCommand, externalAgentAsTool, formatCost, getExternalAgentRegistry, getQuickContext, getRepoTree, isSlashCommand, parseSlashCommand, registerCommand, renderWorkflow, sandboxExec, triggerN8NWebhook } from "./cli/features";
export { createDbAdapter, db, getDefaultDbAdapter, setDefaultDbAdapter } from "./db";
export type { DbAdapter, DbConfig, DbMessage, DbRun, DbTrace } from "./db";
export { MemoryPostgresAdapter, NeonPostgresAdapter, PostgresSessionStorage, createMemoryPostgres, createNeonPostgres, createPostgresSessionStorage } from "./db/postgres";
export { MemoryRedisAdapter, UpstashRedisAdapter, createMemoryRedis, createUpstashRedis } from "./db/redis";
export { SQLiteAdapter, createSQLiteAdapter } from "./db/sqlite";
export { EvalSuite, accuracyEval, performanceEval, reliabilityEval } from "./eval";
export { AgentEventBus, AgentEvents, EventEmitterPubSub, PubSub, createEventBus, createPubSub } from "./events";
export { LLMGuardrail, createLLMGuardrail } from "./guardrails/llm-guardrail";
export { // Computer Use
createComputerUse, ComputerUseClient, createCLIApprovalPrompt, createComputerUseAgent } from "./integrations/computer-use";
export { BaseObservabilityProvider, ConsoleObservabilityProvider, LangfuseObservabilityProvider, MemoryObservabilityProvider, ObservabilityTraceContext, createConsoleObservability, createLangfuseObservability, createMemoryObservability } from "./integrations/observability";
export { // Natural Language Postgres
createNLPostgres, NLPostgresClient, NLPostgresConfig, createPostgresTool } from "./integrations/postgres";
export { // Slack
createSlackBot, SlackBot, parseSlackMessage, verifySlackSignature } from "./integrations/slack";
export { BaseVectorStore, ChromaVectorStore, MemoryVectorStore, PineconeVectorStore, QdrantVectorStore, VectorQueryResult, WeaviateVectorStore, createChromaStore, createMemoryVectorStore, createPineconeStore, createQdrantStore, createWeaviateStore } from "./integrations/vector";
export { BaseVoiceProvider, ElevenLabsVoiceProvider, OpenAIVoiceProvider, createElevenLabsVoice, createOpenAIVoice } from "./integrations/voice";
export { GraphRAG, GraphStore, createGraphRAG } from "./knowledge/graph-rag";
export { BaseReranker, CohereReranker, CrossEncoderReranker, LLMReranker, createCohereReranker, createCrossEncoderReranker, createLLMReranker } from "./knowledge/reranker";
export { // Provider classes
OpenAIProvider, // Provider factory and utilities
createProvider, // Provider registry (extensibility API)
ProviderRegistry, // Types
type LLMProvider, AnthropicProvider, BaseProvider, GoogleProvider, ProviderMessage, ProviderToolDefinition, createProviderRegistry, getAvailableProviders, getDefaultProvider, getDefaultRegistry, hasProvider, isProviderAvailable, listProviders, parseModelString, registerBuiltinProviders, registerProvider, unregisterProvider } from "./llm/providers";
export { ADAPTERS, AISDK_PROVIDERS, COMMUNITY_PROVIDERS, PROVIDER_ALIASES } from "./llm/providers/ai-sdk/types";
export { AutoMemory, AutoMemoryKnowledgeBase, AutoMemoryVectorStore, DEFAULT_POLICIES, createAutoMemory, createLLMSummarizer } from "./memory/auto-memory";
export { FileMemory, createFileMemory } from "./memory/file-memory";
export { Memory, createMemory } from "./memory/memory";
export type { MemoryConfig, MemoryEntry } from "./memory/memory";
export { // Adapters
NoopObservabilityAdapter, // Constants
OBSERVABILITY_TOOLS, // Global adapter management
setObservabilityAdapter, // Types
type SpanKind, ConsoleObservabilityAdapter, MemoryObservabilityAdapter, clearAdapterCache, createConsoleAdapter, createMemoryAdapter, createObservabilityAdapter, getObservabilityAdapter, getObservabilityToolInfo, hasObservabilityToolEnvVar, listObservabilityTools, noopAdapter, resetObservabilityAdapter, trace } from "./observability";
export { Plan, PlanStep, PlanStorage, PlanningAgent, TaskAgent, TodoItem, TodoList, createPlan, createPlanStorage, createPlanningAgent, createTaskAgent, createTodoList } from "./planning";
export { SkillManager, createSkillManager, parseSkillFile } from "./skills";
export { AgentTelemetry, TelemetryCollector, cleanupTelemetry, createAgentTelemetry, disableTelemetry, enableTelemetry, getTelemetry } from "./telemetry";
export { BaseTool, FunctionTool, ToolRegistry, ToolResult, ToolValidationError, createTool, getRegistry, getTool, registerTool, tool, validateTool } from "./tools";
export { airweaveSearch, bedrockBrowserClick, bedrockBrowserFill, bedrockBrowserNavigate, bedrockCodeInterpreter, codeExecution, codeMode, createCustomTool, exaSearch, firecrawlCrawl, firecrawlScrape, parallelSearch, perplexitySearch, registerCustomTool, registerLocalTool, registerNpmTool, superagentGuard, superagentRedact, superagentVerify, tavilyCrawl, tavilyExtract, tavilySearch, valyuBioSearch, valyuCompanyResearch, valyuEconomicsSearch, valyuFinanceSearch, valyuPaperSearch, valyuPatentSearch, valyuSecSearch, valyuWebSearch } from "./tools/builtins";
export { MissingDependencyError, MissingEnvVarError, ToolsRegistry, composeMiddleware, createLoggingMiddleware, createRateLimitMiddleware, createRedactionMiddleware, createRetryMiddleware, createTimeoutMiddleware, createToolsRegistry, createTracingMiddleware, createValidationMiddleware, getToolsRegistry, resetToolsRegistry } from "./tools/registry";
export type { InstallHints, PraisonTool, RedactionHooks, RegisteredTool, ToolCapabilities, ToolExecutionContext, ToolExecutionResult, ToolFactory, ToolHooks, ToolInstallStatus, ToolLimits, ToolLogger, ToolMetadata, ToolMiddleware, ToolParameterProperty, ToolParameterSchema } from "./tools/registry";
export { registerBuiltinTools, tools } from "./tools/tools";
export { Workflow, loop, parallel, repeat, route } from "./workflows";
export type { StepResult, WorkflowContext, WorkflowStep } from "./workflows";
export { createWorkflowFromYAML, loadWorkflowFromFile, parseYAMLWorkflow, validateWorkflowDefinition } from "./workflows/yaml-parser";
```
# Optional Plugins
External tools are available via `praisonai-tools` package:
```bash
pip install praisonai-tools
```
See [PraisonAI-tools](https://github.com/MervinPraison/PraisonAI-tools) for available tools.
+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>=3.5.9" \
"praisonai>=3.9.2" \
"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>=3.5.9" \
"praisonai>=3.9.2" \
"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>=3.5.9" \
"praisonai>=3.9.2" \
"praisonai[ui]" \
"praisonai[crewai]"
+16
View File
@@ -23,6 +23,7 @@ examples/
| Category | Examples | Docs |
|----------|----------|------|
| **Consolidated Params** | [consolidated_params/](consolidated_params/) | [📖](https://docs.praison.ai/api/consolidated-params) |
| **Agents** | [python/agents/](python/agents/) | [📖](https://docs.praison.ai/concepts/agents) |
| **Workflows** | [python/workflows/](python/workflows/) | [📖](https://docs.praison.ai/features/workflows) |
| **Model Router** | [python/agents/router-agent-cost-optimization.py](python/agents/router-agent-cost-optimization.py) | [📖](https://docs.praison.ai/features/model-router) |
@@ -35,6 +36,21 @@ examples/
| **Serve** | [serve/](serve/) | [📖](https://docs.praison.ai/cli/serve) |
| **Endpoints** | [serve/](serve/) | [📖](https://docs.praison.ai/cli/endpoints) |
## Consolidated Params Examples
Agent-centric API with unified parameter resolution. Precedence: Instance > Config > Array > Dict > String > Bool > Default
| Example | Description |
|---------|-------------|
| [basic_agent.py](consolidated_params/basic_agent.py) | Minimal agent with memory |
| [basic_agents.py](consolidated_params/basic_agents.py) | Multi-agent with memory+planning |
| [basic_workflow.py](consolidated_params/basic_workflow.py) | Workflow with consolidated params |
| [basic_memory.py](consolidated_params/basic_memory.py) | Memory presets (file, redis, postgres) |
| [basic_guardrails.py](consolidated_params/basic_guardrails.py) | Guardrails with callable or config |
| [basic_workflow_agentlike.py](consolidated_params/basic_workflow_agentlike.py) | Workflow with agent-like params |
| [basic_step_override.py](consolidated_params/basic_step_override.py) | Step-level override of workflow defaults |
| [advanced_workflow_full_features.py](consolidated_params/advanced_workflow_full_features.py) | All consolidated params |
## Serve Examples
| Example | Description | CLI Command |
+96
View File
@@ -0,0 +1,96 @@
# Consolidated Params Examples
Examples demonstrating the **Agent-Centric API** with consolidated parameters.
## Precedence Ladder
```
Instance > Config > Array > Dict > String > Bool > Default
```
## Quick Reference
| Feature | Presets | Example |
|---------|---------|---------|
| `memory` | file, sqlite, redis, postgres, mem0, mongodb | `memory="sqlite"` |
| `output` | minimal, normal, verbose, debug, silent | `output="verbose"` |
| `execution` | fast, balanced, thorough, unlimited | `execution="balanced"` |
| `planning` | reasoning, read_only, auto | `planning="reasoning"` |
| `reflection` | minimal, standard, thorough | `reflection="standard"` |
| `guardrails` | strict, permissive, safety | `guardrails="strict"` |
| `web` | duckduckgo, tavily, google, bing, serper | `web="duckduckgo"` |
| `context` | sliding_window, summarize, truncate | `context="sliding_window"` |
| `autonomy` | suggest, auto_edit, full_auto | `autonomy="suggest"` |
| `caching` | enabled, disabled, prompt | `caching="prompt"` |
## Examples
### Basic Examples (Single Feature)
| File | Feature | Description |
|------|---------|-------------|
| `basic_agent.py` | Agent | Minimal agent with memory |
| `basic_memory.py` | memory | SQLite memory preset |
| `basic_output.py` | output | Verbose output preset |
| `basic_execution.py` | execution | Execution control |
| `basic_guardrails.py` | guardrails | Callable validator |
| `basic_reflection.py` | reflection | Self-reflection preset |
| `basic_web.py` | web | Web search preset |
| `basic_planning.py` | planning | Planning preset |
| `basic_autonomy.py` | autonomy | Autonomy preset |
| `basic_caching.py` | caching | Caching preset |
| `basic_knowledge.py` | knowledge | RAG with sources |
| `basic_context.py` | context | Context management |
| `basic_hooks.py` | hooks | Lifecycle callbacks |
### Multi-Agent Examples
| File | Description |
|------|-------------|
| `basic_agents.py` | Multi-agent with memory and planning |
### Workflow Examples
| File | Description |
|------|-------------|
| `basic_workflow.py` | Simple workflow with output preset |
| `basic_workflow_agentlike.py` | Workflow with agent-like params |
| `basic_step_override.py` | Step-level param overrides |
| `advanced_workflow_full_features.py` | All consolidated params |
### Advanced Examples
| File | Description |
|------|-------------|
| `advanced_output_execution.py` | Combined output + execution |
## Usage Forms
Each consolidated param supports multiple input forms:
```python
# Bool - enable with defaults
memory=True
# String preset
memory="sqlite"
# Dict config
memory={"backend": "sqlite", "user_id": "user123"}
# Config instance
memory=MemoryConfig(backend="sqlite", user_id="user123")
# Array with overrides (for some params)
guardrails=["strict", {"max_retries": 10}]
```
## Running Examples
```bash
# Set API key
export OPENAI_API_KEY=your_key_here
# Run any example
python basic_agent.py
```
@@ -0,0 +1,17 @@
"""
Advanced Output + Execution Example - Agent-Centric API
Demonstrates preset + override array syntax.
"""
from praisonaiagents import Agent
# Advanced: Preset with overrides using array syntax
agent = Agent(
instructions="You are a helpful assistant.",
output=["verbose", {"stream": True, "metrics": True}],
execution=["thorough", {"max_iter": 30}],
)
response = agent.start("Explain quantum computing in simple terms.")
print(response)
@@ -0,0 +1,55 @@
"""Advanced Workflow with all consolidated params configured."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
from praisonaiagents.workflows.workflow_configs import (
WorkflowOutputConfig, WorkflowPlanningConfig, WorkflowMemoryConfig,
)
# Full-featured workflow with all consolidated params
workflow = Workflow(
name="FullFeaturedWorkflow",
description="Demonstrates all agent-like consolidated params",
steps=[
WorkflowStep(
name="researcher",
action="Research: {{input}}",
agent=Agent(instructions="You are a researcher."),
knowledge=["research_docs/"], # Step-specific knowledge
web="duckduckgo", # Use DuckDuckGo for this step
),
WorkflowStep(
name="analyzer",
action="Analyze the research",
agent=Agent(instructions="You are an analyst."),
reflection="thorough", # Thorough reflection for analysis
guardrails="strict", # Strict validation
),
WorkflowStep(
name="writer",
action="Write the final report",
agent=Agent(instructions="You are a writer."),
autonomy=True, # Enable autonomy for writing
),
],
# Workflow-level consolidated params
output=WorkflowOutputConfig(verbose=True, stream=True),
planning=WorkflowPlanningConfig(enabled=True, reasoning=True),
memory=WorkflowMemoryConfig(backend="file"),
# Agent-like params
autonomy=True,
knowledge=["shared_docs/"],
guardrails=True,
web=True,
reflection=True,
)
if __name__ == "__main__":
print(f"Workflow: {workflow.name}")
print(f"Output verbose: {workflow._verbose}")
print(f"Planning enabled: {workflow._planning_enabled}")
print(f"Memory config: {workflow._memory_config}")
print(f"Autonomy: {workflow.autonomy}")
print(f"Knowledge: {workflow.knowledge}")
print(f"Guardrails: {workflow.guardrails}")
print(f"Web: {workflow.web}")
print(f"Reflection: {workflow.reflection}")
@@ -0,0 +1,12 @@
"""Basic Agent example with consolidated params."""
from praisonaiagents import Agent
# Minimal agent with memory
agent = Agent(
instructions="You are a helpful assistant.",
memory=True,
)
if __name__ == "__main__":
response = agent.chat("Hello!")
print(response)
@@ -0,0 +1,17 @@
"""Basic Agents (multi-agent) example with consolidated params."""
from praisonaiagents import Agent, Agents
# Create agents
writer = Agent(instructions="You write content.")
editor = Agent(instructions="You edit content.")
# Multi-agent with consolidated params
agents = Agents(
agents=[writer, editor],
memory=True,
planning=True,
)
if __name__ == "__main__":
result = agents.start("Write a haiku about AI")
print(result)
@@ -0,0 +1,18 @@
"""
Basic Autonomy Example - Agent-Centric API
Demonstrates autonomy with consolidated params.
Presets: suggest, auto_edit, full_auto
"""
from praisonaiagents import Agent
# Basic: Enable autonomy with preset
agent = Agent(
instructions="You are an autonomous assistant.",
autonomy="suggest", # Presets: suggest, auto_edit, full_auto
)
if __name__ == "__main__":
response = agent.start("Help me organize my project files.")
print(response)
@@ -0,0 +1,23 @@
"""
Basic Caching Example - Agent-Centric API
Demonstrates caching with consolidated params.
Presets: enabled, disabled, prompt
"""
from praisonaiagents import Agent
# Basic: Enable caching with preset
agent = Agent(
instructions="You are a helpful assistant with caching enabled.",
caching="prompt", # Presets: enabled, disabled, prompt
)
if __name__ == "__main__":
# First call - will cache
response = agent.start("What is the capital of France?")
print(response)
# Second call - may use cache
response = agent.start("What is the capital of France?")
print(response)
@@ -0,0 +1,18 @@
"""
Basic Context Example - Agent-Centric API
Demonstrates context management with consolidated params.
Presets: sliding_window, summarize, truncate
"""
from praisonaiagents import Agent
# Basic: Enable context management with preset
agent = Agent(
instructions="You are a helpful assistant with context management.",
context="sliding_window", # Presets: sliding_window, summarize, truncate
)
if __name__ == "__main__":
response = agent.start("Tell me a long story about a dragon.")
print(response)
@@ -0,0 +1,16 @@
"""
Basic Execution Example - Agent-Centric API
Demonstrates execution preset usage.
"""
from praisonaiagents import Agent
# Basic: Use fast execution preset
agent = Agent(
instructions="You are a helpful assistant.",
execution="fast", # Presets: fast, balanced, thorough, unlimited
)
response = agent.start("What is the capital of France?")
print(response)
@@ -0,0 +1,26 @@
"""
Basic Guardrails Example - Agent-Centric API
Demonstrates guardrails with callable validator.
"""
from praisonaiagents import Agent
# Define a simple guardrail validator
def validate_response(output):
"""Validate that response doesn't contain forbidden words."""
forbidden = ["error", "fail", "cannot"]
text = str(output).lower()
for word in forbidden:
if word in text:
return (False, f"Response contains forbidden word: {word}")
return (True, output)
# Basic: Use callable guardrail
agent = Agent(
instructions="You are a helpful assistant.",
guardrails=validate_response,
)
response = agent.start("What is 2 + 2?")
print(response)
@@ -0,0 +1,28 @@
"""
Basic Hooks Example - Agent-Centric API
Demonstrates lifecycle hooks with consolidated params.
Valid keys: on_step, on_tool_call, middleware
"""
from praisonaiagents import Agent
# Define hook callbacks
def on_step_callback(step_info):
print(f"Step: {step_info}")
def on_tool_call_callback(tool_info):
print(f"Tool called: {tool_info}")
# Basic: Enable hooks with dict
agent = Agent(
instructions="You are a helpful assistant.",
hooks={
"on_step": on_step_callback,
"on_tool_call": on_tool_call_callback,
},
)
if __name__ == "__main__":
response = agent.start("What is 2 + 2?")
print(response)
@@ -0,0 +1,18 @@
"""
Basic Knowledge (RAG) Example - Agent-Centric API
Demonstrates knowledge with consolidated params.
Supports: bool, list of sources, dict config, KnowledgeConfig
"""
from praisonaiagents import Agent
# Basic: Enable knowledge with list of sources
agent = Agent(
instructions="You are a helpful assistant with document knowledge.",
knowledge=["docs/"], # List of file/folder paths
)
if __name__ == "__main__":
response = agent.start("What does the documentation say about installation?")
print(response)
@@ -0,0 +1,21 @@
"""
Basic Memory Example - Agent-Centric API
Demonstrates the simplest memory usage with consolidated params.
"""
from praisonaiagents import Agent
# Basic: Enable memory with preset
agent = Agent(
instructions="You are a helpful assistant with memory.",
memory="sqlite", # Preset: sqlite, redis, postgres, file
)
# Run a simple task
response = agent.start("Remember that my favorite color is blue.")
print(response)
# Follow-up to test memory
response = agent.start("What is my favorite color?")
print(response)
@@ -0,0 +1,16 @@
"""
Basic Output Example - Agent-Centric API
Demonstrates output preset usage.
"""
from praisonaiagents import Agent
# Basic: Use verbose output preset
agent = Agent(
instructions="You are a helpful assistant.",
output="verbose", # Presets: minimal, normal, verbose, debug, silent
)
response = agent.start("What is 2 + 2?")
print(response)
@@ -0,0 +1,18 @@
"""
Basic Planning Example - Agent-Centric API
Demonstrates planning with consolidated params.
Presets: reasoning, read_only, auto
"""
from praisonaiagents import Agent
# Basic: Enable planning with preset
agent = Agent(
instructions="You are a strategic planner.",
planning="reasoning", # Presets: reasoning, read_only, auto
)
if __name__ == "__main__":
response = agent.start("Plan a 3-day trip to Tokyo.")
print(response)
@@ -0,0 +1,18 @@
"""
Basic Reflection Example - Agent-Centric API
Demonstrates reflection (self-reflect) with consolidated params.
Presets: minimal, standard, thorough
"""
from praisonaiagents import Agent
# Basic: Enable reflection with preset
agent = Agent(
instructions="You are a helpful assistant that reflects on your answers.",
reflection="standard", # Presets: minimal, standard, thorough
)
if __name__ == "__main__":
response = agent.start("Explain quantum computing in simple terms.")
print(response)
@@ -0,0 +1,33 @@
"""Basic example showing step-level override of workflow defaults."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
# Workflow with defaults
workflow = Workflow(
name="StepOverrideWorkflow",
steps=[
WorkflowStep(
name="step1",
action="Process with workflow defaults",
agent=Agent(instructions="You are a processor."),
# Uses workflow-level web=True (inherited)
),
WorkflowStep(
name="step2",
action="Process with step override",
agent=Agent(instructions="You are a processor."),
# Override workflow default
web=False, # Disable web for this step
reflection="thorough", # Use thorough reflection preset
),
],
# Workflow defaults
web=True,
reflection=True,
)
if __name__ == "__main__":
print(f"Workflow web default: {workflow.web}")
print(f"Step1 web: {workflow.steps[0].web}") # None (uses workflow default)
print(f"Step2 web: {workflow.steps[1].web}") # False (overridden)
print(f"Step2 reflection: {workflow.steps[1].reflection}") # thorough
+18
View File
@@ -0,0 +1,18 @@
"""
Basic Web Search Example - Agent-Centric API
Demonstrates web search with consolidated params.
Presets: duckduckgo, tavily, google, bing, serper, search_only, fetch_only
"""
from praisonaiagents import Agent
# Basic: Enable web search with preset
agent = Agent(
instructions="You are a research assistant with web access.",
web="duckduckgo", # Presets: duckduckgo, tavily, google, bing, serper
)
if __name__ == "__main__":
response = agent.start("What are the latest AI developments in 2024?")
print(response)
@@ -0,0 +1,26 @@
"""
Basic Workflow Example - Agent-Centric API
Demonstrates minimal workflow with consolidated params.
"""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
# Create a simple workflow
workflow = Workflow(
name="simple_workflow",
output="verbose", # Workflow-level output preset
)
# Add a step
step = WorkflowStep(
name="writer",
action="Write a haiku about programming",
agent=Agent(instructions="You are a creative poet."),
output="result.txt", # Save output to file
)
# Note: This is a structural example - actual execution requires workflow.run()
print("Workflow created with output preset:", workflow.output)
print("Step output file:", step.output_file)
@@ -0,0 +1,32 @@
"""Basic Workflow with Agent-like consolidated params."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
# Workflow with agent-like params (knowledge, web, guardrails, reflection)
workflow = Workflow(
name="AgentLikeWorkflow",
steps=[
WorkflowStep(
name="researcher",
action="Research the topic: {{input}}",
agent=Agent(instructions="You are a researcher."),
),
WorkflowStep(
name="writer",
action="Write about the research findings",
agent=Agent(instructions="You are a writer."),
),
],
# Agent-like consolidated params
knowledge=["docs/"], # Enable RAG
web=True, # Enable web search
guardrails=True, # Enable guardrails
reflection=True, # Enable self-reflection
)
if __name__ == "__main__":
print(f"Workflow: {workflow.name}")
print(f"Knowledge: {workflow.knowledge}")
print(f"Web: {workflow.web}")
print(f"Guardrails: {workflow.guardrails}")
print(f"Reflection: {workflow.reflection}")
@@ -22,7 +22,7 @@ agents: # Canonical: use 'agents' instead of 'roles'
verbose: true
allow_delegation: false
llm:
model: "gpt-5-nano"
model: "gpt-4o-mini"
temperature: 0.3
tools:
- "InternetSearchTool"
@@ -76,7 +76,7 @@ agents: # Canonical: use 'agents' instead of 'roles'
verbose: true
allow_delegation: false
llm:
model: "gpt-5-nano"
model: "gpt-4o-mini"
temperature: 0.3
tools:
- "InternetSearchTool"
@@ -130,7 +130,7 @@ agents: # Canonical: use 'agents' instead of 'roles'
verbose: true
allow_delegation: false
llm:
model: "gpt-5-nano"
model: "gpt-4o-mini"
temperature: 0.3
tools:
- "InternetSearchTool"
@@ -185,7 +185,7 @@ agents: # Canonical: use 'agents' instead of 'roles'
verbose: true
allow_delegation: false
llm:
model: "gpt-5-nano"
model: "gpt-4o-mini"
temperature: 0.4
tools:
- "InternetSearchTool"
@@ -239,7 +239,7 @@ agents: # Canonical: use 'agents' instead of 'roles'
verbose: true
allow_delegation: false
llm:
model: "gpt-5-nano"
model: "gpt-4o-mini"
temperature: 0.3
tools:
- "InternetSearchTool"
@@ -299,7 +299,7 @@ agents: # Canonical: use 'agents' instead of 'roles'
verbose: true
allow_delegation: false
llm:
model: "gpt-5-nano"
model: "gpt-4o-mini"
temperature: 0.3
tasks:
report_synthesis:
+148
View File
@@ -0,0 +1,148 @@
"""
Multi-Server MCP Example.
This example demonstrates how to use multiple MCP servers with PraisonAI Agents,
including mixing MCP tools with regular Python function tools.
Requirements:
- Node.js and npx installed (or uvx for Python-based servers)
- pip install praisonaiagents[mcp]
- OPENAI_API_KEY environment variable set
Usage:
python multi_server.py
"""
from praisonaiagents import Agent, MCP
import os
def calculate(expression: str) -> str:
"""
A simple calculator tool that evaluates mathematical expressions.
Args:
expression: A mathematical expression to evaluate (e.g., "2 + 2")
Returns:
The result of the calculation
"""
try:
# Safe evaluation of mathematical expressions
allowed_chars = set("0123456789+-*/.() ")
if not all(c in allowed_chars for c in expression):
return "Error: Invalid characters in expression"
result = eval(expression)
return f"Result: {result}"
except Exception as e:
return f"Error: {str(e)}"
def main():
# Check for API key
if not os.environ.get("OPENAI_API_KEY"):
print("Please set OPENAI_API_KEY environment variable")
return
print("=" * 60)
print("Multi-Server MCP Example")
print("=" * 60)
# Create MCP instance with Time server
print("\nInitializing MCP servers...")
try:
time_mcp = MCP("uvx mcp-server-time", timeout=30)
print("✓ Time MCP server initialized")
except Exception as e:
print(f"✗ Time MCP server failed: {e}")
return
# Create an agent with multiple tool sources
agent = Agent(
name="MultiToolAgent",
instructions="""You are a helpful assistant with access to multiple tools:
1. Time tools - for getting current time in different timezones
2. Calculator - for mathematical calculations
Use the appropriate tool based on the user's request.""",
llm="openai/gpt-4o-mini",
tools=[time_mcp, calculate] # Mix MCP and regular tools
)
# Show available tools
print("\nAvailable tools:")
formatted_tools = agent._format_tools_for_completion(agent.tools)
for tool in formatted_tools:
print(f" - {tool['function']['name']}: {tool['function']['description'][:50]}...")
# Example queries
queries = [
"What time is it in Tokyo?",
"Calculate 15 * 7 + 23",
"What's the current time in New York and London?"
]
print("\n" + "=" * 60)
print("Running queries...")
print("=" * 60)
for i, query in enumerate(queries, 1):
print(f"\n--- Query {i} ---")
print(f"Question: {query}\n")
try:
response = agent.chat(query)
print(f"Response:\n{response}")
except Exception as e:
print(f"Error: {e}")
print("-" * 40)
# Clean up
time_mcp.shutdown()
print("\nDone!")
def demo_multiple_mcp_servers():
"""
Demonstrate using multiple MCP servers simultaneously.
This function shows how to create agents with multiple MCP servers,
each providing different capabilities.
"""
print("\n" + "=" * 60)
print("Multiple MCP Servers Demo")
print("=" * 60)
# Initialize multiple MCP servers
servers = {}
try:
servers['time'] = MCP("uvx mcp-server-time", timeout=30)
print("✓ Time server initialized")
except Exception as e:
print(f"✗ Time server failed: {e}")
# Create agent with all available servers
available_tools = list(servers.values())
if not available_tools:
print("No MCP servers available")
return
agent = Agent(
name="MultiServerAgent",
instructions="You have access to multiple MCP servers. Use the appropriate tools.",
llm="openai/gpt-4o-mini",
tools=available_tools
)
print(f"\nAgent created with {len(available_tools)} MCP server(s)")
# Clean up
for server in servers.values():
server.shutdown()
if __name__ == "__main__":
main()
+70
View File
@@ -0,0 +1,70 @@
"""
Sequential Thinking MCP Example.
This example demonstrates how to use the Sequential Thinking MCP server
with PraisonAI Agents to break down complex problems step by step.
Requirements:
- Node.js and npx installed
- pip install praisonaiagents[mcp]
- OPENAI_API_KEY environment variable set
Usage:
python sequential_thinking.py
"""
from praisonaiagents import Agent, MCP
import os
def main():
# Check for API key
if not os.environ.get("OPENAI_API_KEY"):
print("Please set OPENAI_API_KEY environment variable")
return
# Create MCP instance with Sequential Thinking server
# The server provides tools for step-by-step problem analysis
sequential_mcp = MCP(
"npx -y @modelcontextprotocol/server-sequential-thinking",
timeout=60
)
# Create an agent with the Sequential Thinking tools
agent = Agent(
name="ProblemSolver",
instructions="""You are an expert problem solver who breaks down complex problems
into manageable steps. When given a problem:
1. Use the sequential thinking tool to analyze it step by step
2. Provide clear, actionable steps
3. Explain your reasoning at each step""",
llm="openai/gpt-4o-mini",
tools=sequential_mcp
)
# Example problems to solve
problems = [
"Break down the process of making a cup of tea",
"How would you plan a weekend trip to a new city?",
"What steps would you take to learn a new programming language?"
]
print("=" * 60)
print("Sequential Thinking MCP Example")
print("=" * 60)
for i, problem in enumerate(problems, 1):
print(f"\n--- Problem {i} ---")
print(f"Question: {problem}\n")
response = agent.chat(problem)
print(f"Response:\n{response}")
print("-" * 40)
# Clean up
sequential_mcp.shutdown()
print("\nDone!")
if __name__ == "__main__":
main()
@@ -46,7 +46,7 @@ agent = RouterAgent(
name="Smart Assistant",
role="Adaptive AI Assistant",
goal="Complete tasks using the most appropriate model",
models=["gpt-5-nano", "gpt-5-nano", "claude-3-5-sonnet-20241022"],
models=["gpt-4o-mini", "gpt-4o-mini", "claude-3-5-sonnet-20241022"],
routing_strategy="auto" # Automatic model selection
)
@@ -90,7 +90,7 @@ analyzer = RouterAgent(
goal="Analyze data efficiently",
models={
"gemini/gemini-1.5-flash": {},
"gpt-5-nano": {},
"gpt-4o-mini": {},
"claude-3-haiku-20240307": {}
},
model_router=router,
@@ -207,7 +207,7 @@ for i, agent in enumerate(auto.agents):
name=agent.name,
role=agent.role,
goal=agent.goal,
models=["gpt-5-nano", "gpt-5-nano", "claude-3-5-sonnet"],
models=["gpt-4o-mini", "gpt-4o-mini", "claude-3-5-sonnet"],
routing_strategy="auto"
)
+1 -1
View File
@@ -97,7 +97,7 @@ researcher = Agent(
name="Researcher",
role="Information Researcher",
goal="Store information with semantic understanding",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create task
+1 -1
View File
@@ -17,7 +17,7 @@ def my_function():
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
with track_api_call("agent_request"):
+1 -1
View File
@@ -13,7 +13,7 @@ agent = Agent(
role="Assistant",
goal="Help users",
backstory="You are helpful.",
llm="gpt-5-nano",
llm="gpt-4o-mini",
metrics=True # 🎯 That's it!
)
@@ -177,7 +177,7 @@ Set your API keys:
```bash
export OPENAI_API_KEY="your-api-key"
export OPENAI_MODEL_NAME="gpt-5-nano"
export OPENAI_MODEL_NAME="gpt-4o-mini"
```
## 📝 Customization
@@ -38,7 +38,7 @@ def main():
# Create agent
agent = Agent(
instructions="You are a helpful assistant that explains scientific concepts simply",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Track the API call performance
@@ -13,8 +13,8 @@ def main():
role="Research Specialist",
goal="Find information about a topic",
backstory="You are an expert researcher who finds comprehensive information.",
verbose=True,
llm="gpt-5-nano", # Use a cost-effective model for examples
output="verbose",
llm="gpt-4o-mini", # Use a cost-effective model for examples
metrics=True # 🎯 SIMPLIFIED: Just add this parameter!
)
@@ -29,7 +29,7 @@ def main():
agents = Agents(
agents=[research_agent],
tasks=[research_task],
verbose=True
output="verbose"
)
print("🚀 Running agent task...")
@@ -54,7 +54,7 @@ def create_agents():
goal="Gather comprehensive information on renewable energy",
backstory="Expert researcher with deep knowledge of energy sector",
instructions="You are a thorough researcher. Provide detailed, fact-based information.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
analyst = Agent(
@@ -63,7 +63,7 @@ def create_agents():
goal="Analyze trends and patterns in renewable energy data",
backstory="Experienced data analyst specializing in energy markets",
instructions="You are an analytical thinker. Focus on trends, patterns, and insights.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
writer = Agent(
@@ -72,7 +72,7 @@ def create_agents():
goal="Create clear, compelling reports",
backstory="Professional technical writer with expertise in energy sector",
instructions="You are a skilled writer. Create clear, well-structured reports.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
return researcher, analyst, writer
@@ -104,8 +104,7 @@ def main():
workflow = Agents(
agents=[researcher, analyst, writer],
tasks=[research_task, analysis_task, report_task],
process="sequential",
verbose=True
process="sequential"
)
result = workflow.start()
@@ -11,7 +11,7 @@ Shows how to monitor agent performance when using external tools.
"""
from praisonaiagents import Agent
from praisonaiagents.tools import duckduckgo, wikipedia
from praisonaiagents.tools import duckduckgo, wikipedia_tools
from praisonaiagents.telemetry import (
monitor_function, track_api_call, get_api_stats,
get_slowest_functions, performance_monitor
@@ -48,8 +48,8 @@ def main():
instructions="""You are a research assistant that helps find information.
Use the available tools to search for information and provide comprehensive answers.
Be thorough in your research and cite your sources.""",
llm="gpt-5-nano",
tools=[duckduckgo, wikipedia] # Add search tools
llm="gpt-4o-mini",
tools=[duckduckgo, wikipedia_tools] # Add search tools
)
# Test queries to demonstrate tool performance monitoring
@@ -97,7 +97,9 @@ def main():
# Slowest functions analysis
print("\n🐌 Slowest Functions:")
slowest = get_slowest_functions()
for func_name, avg_time in slowest:
for item in slowest[:5]:
func_name = item.get('function', 'unknown')
avg_time = item.get('average_time', 0)
print(f" {func_name}: {avg_time:.3f}s average")
# Real-time performance data
@@ -54,7 +54,7 @@ async def run_async_agent(query: str):
# Create agent
agent = Agent(
instructions="You are an efficient AI assistant that processes requests quickly",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Track the agent execution
@@ -60,7 +60,7 @@ def run_robust_agent(query: str, with_error_simulation: bool = True):
instructions="""You are a resilient AI assistant.
Even when facing challenges, you provide helpful responses.
If you encounter errors, acknowledge them and offer alternatives.""",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
try:
@@ -65,7 +65,7 @@ def run_stateful_agent(query: str, session_id: str, conversation_turn: int):
instructions="""You are a memory-enabled AI assistant. You can remember
previous conversations and build on past interactions. Use your memory
to provide personalized and contextual responses.""",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Pre-processing: retrieve relevant memories
@@ -165,7 +165,9 @@ def main():
# Slowest operations
print("\n🐌 Slowest Memory Operations:")
slowest = get_slowest_functions()
for func_name, avg_time in slowest[:5]: # Top 5 slowest
for item in slowest[:5]: # Top 5 slowest
func_name = item.get('function', 'unknown')
avg_time = item.get('average_time', 0)
print(f" {func_name}: {avg_time:.3f}s average")
# Memory operation breakdown
@@ -77,7 +77,7 @@ def run_hierarchical_workflow():
backstory="Experienced project manager with expertise in team coordination",
instructions="""You are a project manager. Break down complex projects into tasks,
assign them to appropriate team members, and coordinate the overall effort.""",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create worker agents
@@ -87,7 +87,7 @@ def run_hierarchical_workflow():
goal="Conduct thorough research on assigned topics",
backstory="Expert researcher with deep analytical skills",
instructions="You are a research specialist. Provide detailed, factual information.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
analysis_worker = Agent(
@@ -96,7 +96,7 @@ def run_hierarchical_workflow():
goal="Analyze data and identify patterns and insights",
backstory="Experienced data analyst with strong analytical thinking",
instructions="You are a data analyst. Focus on patterns, trends, and insights.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
writing_worker = Agent(
@@ -105,7 +105,7 @@ def run_hierarchical_workflow():
goal="Create clear, well-structured documentation and reports",
backstory="Professional writer specializing in technical content",
instructions="You are a technical writer. Create clear, comprehensive reports.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Project tasks
@@ -180,7 +180,7 @@ def run_agent_with_custom_tools():
instructions="""You are a technical assistant with access to various tools.
Use the appropriate tools to help with data processing, API calls, database queries,
and file operations. Always explain what tools you're using and why.""",
llm="gpt-5-nano",
llm="gpt-4o-mini",
tools=[process_data, call_external_api, query_database, file_operation]
)
@@ -263,7 +263,7 @@ def main():
# Slowest operations
print("\n🐌 Slowest Tool Operations:")
slowest = get_slowest_functions()
tool_slowest = [(name, time) for name, time in slowest if 'tool' in name.lower()]
tool_slowest = [(item.get('function', 'unknown'), item.get('average_time', 0)) for item in slowest if 'tool' in item.get('function', '').lower()]
for tool_name, avg_time in tool_slowest[:3]:
print(f" {tool_name}: {avg_time:.3f}s")
@@ -60,7 +60,7 @@ def get_real_time_agent_response(query: str, response_id: int):
# Create a lightweight agent for streaming
agent = Agent(
instructions="You are a real-time assistant. Provide quick, helpful responses.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
with track_api_call(f"streaming_response_{response_id}"):
@@ -42,19 +42,19 @@ def collect_comprehensive_data():
agents = {
'quick_agent': Agent(
instructions="You are a quick-response agent. Provide concise answers.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
),
'analytical_agent': Agent(
instructions="You are an analytical agent. Provide detailed analysis.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
),
'research_agent': Agent(
instructions="You are a research agent. Provide comprehensive information.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
),
'creative_agent': Agent(
instructions="You are a creative agent. Provide imaginative responses.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
}
@@ -98,19 +98,19 @@ def simulate_complex_workflow():
planner = Agent(
name="planner",
instructions="You are a project planner. Break down tasks and plan execution.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
executor = Agent(
name="executor",
instructions="You are a task executor. Complete assigned tasks efficiently.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
reviewer = Agent(
name="reviewer",
instructions="You are a quality reviewer. Review and improve work.",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create workflow tasks
@@ -302,13 +302,17 @@ def display_dashboard(dashboard_data, benchmark_results):
perf_data = dashboard_data['performance_data']
print(" Fastest Functions:")
fastest_functions = sorted(perf_data['slowest_functions'], key=lambda x: x[1])[:3]
for name, time in fastest_functions:
print(f" {name}: {time:.3f}s")
fastest_functions = sorted(perf_data['slowest_functions'], key=lambda x: x.get('average_time', float('inf')))[:3]
for item in fastest_functions:
name = item.get('function', 'unknown')
time_val = item.get('average_time', 0)
print(f" {name}: {time_val:.3f}s")
print(" Slowest Functions:")
for name, time in perf_data['slowest_functions'][:3]:
print(f" {name}: {time:.3f}s")
for item in perf_data['slowest_functions'][:3]:
name = item.get('function', 'unknown')
time_val = item.get('average_time', 0)
print(f" {name}: {time_val:.3f}s")
# Benchmark Results
print(f"\n⚡ BENCHMARK RESULTS")
-279
View File
@@ -1,279 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
PraisonAI Agents is a hierarchical AI agent framework for completing complex tasks with self-reflection capabilities. It supports multi-agent collaboration, tool integration, and various execution patterns (sequential, hierarchical, parallel).
## Development Commands
### Installation and Setup
```bash
# Install core package
pip install -e .
# Install with specific features
pip install -e .[all] # All features
pip install -e .[memory] # Memory capabilities
pip install -e .[knowledge] # Document processing
pip install -e .[mcp] # MCP server support
pip install -e .[llm] # Extended LLM support
pip install -e .[api] # API server capabilities
```
### Testing
```bash
# Run individual test examples (no formal test runner configured)
python tests/basic-agents.py
python tests/async_example.py
python tests/knowledge-agents.py
# Test specific features
python tests/mcp-agents.py # MCP integration
python tests/memory_example.py # Memory functionality
python tests/tools_example.py # Tool system
```
### Running Examples
```bash
# Basic agent usage
python tests/single-agent.py
# Multi-agent workflows
python tests/multi-agents-api.py
# Async operations
python tests/async_example_full.py
# MCP server examples
python tests/mcp-sse-direct-server.py # Start MCP server
python tests/mcp-sse-direct-client.py # Connect to server
```
## Core Architecture
### Agent System (`praisonaiagents/agent/`)
- **Agent**: Core agent class with LLM integration, tool calling, and self-reflection
- **ImageAgent**: Specialized multimodal agent for image processing
- Self-reflection with configurable min/max iterations (default: 1-3)
- Delegation support for hierarchical agent structures
### Multi-Agent Orchestration (`praisonaiagents/agents/`)
- **PraisonAIAgents**: Main orchestrator for managing multiple agents and tasks
- **AutoAgents**: Automatic agent creation and management
- Process types: `sequential`, `hierarchical`, `parallel`
- Context passing between agents and task dependency management
### Task System (`praisonaiagents/task/`)
- **Task**: Core task definition with context, callbacks, and output specifications
- Supports file output, JSON/Pydantic structured output, async execution
- Conditional logic with `condition` parameter for task flow control
- Context passing via `context` parameter for task dependencies
- **Guardrails**: Built-in validation and safety mechanisms for task outputs
- Function-based guardrails for custom validation logic
- LLM-based guardrails using natural language descriptions
- Automatic retry with configurable `max_retries` parameter
- Compatible with CrewAI guardrail patterns
### LLM Integration (`praisonaiagents/llm/`)
- Unified wrapper for multiple LLM providers via LiteLLM
- Supports OpenAI, Anthropic, Gemini, DeepSeek, local models (Ollama)
- Context length management and tool calling capabilities
- Set via `llm` parameter on agents or global `OPENAI_API_KEY`/`ANTHROPIC_API_KEY`
### Tool System (`praisonaiagents/tools/`)
Two implementation patterns:
1. **Function-based**: Simple tools using `@tool` decorator
2. **Class-based**: Complex tools inheriting from `BaseTool`
Built-in tools include: DuckDuckGo search, file operations, calculator, Wikipedia, arXiv, data analysis tools, shell execution.
### Memory & Knowledge Systems
- **Memory** (`praisonaiagents/memory/`): Multi-layered memory with RAG support
- Types: short-term, long-term, entity, user memory
- Providers: ChromaDB, Mem0, custom implementations
- **Knowledge** (`praisonaiagents/knowledge/`): Document processing with chunking
- Chunking strategies via `chonkie` library
- Embedding and retrieval capabilities
### MCP (Model Context Protocol) Integration
- **MCP Server**: Server-side tool protocol for distributed execution
- **SSE Support**: Server-sent events for real-time communication
- Tool discovery and dynamic registration
## Development Patterns
### Agent Creation
```python
agent = Agent(
name="Agent Name",
role="Agent Role",
goal="Agent Goal",
backstory="Agent Background",
llm="gpt-5-nano", # or other LLM
self_reflect=True, # Enable self-reflection
min_reflect=1, # Minimum reflection iterations
max_reflect=3, # Maximum reflection iterations
tools=[tool1, tool2], # Optional tools
guardrail=validate_function, # Agent-level guardrail (function or string)
max_guardrail_retries=3 # Retry limit for guardrail failures
)
```
### Task Definition
```python
task = Task(
name="task_name",
description="Task description",
expected_output="Expected output format",
agent=agent,
context=[previous_task], # Task dependencies
output_pydantic=ResponseModel, # Structured output
condition="condition_function" # Conditional execution
)
```
### Guardrails Usage
#### Task-Level Guardrails
```python
from typing import Tuple, Any
from praisonaiagents import GuardrailResult
# Function-based guardrail (Option 1: Using GuardrailResult)
def validate_output(task_output: TaskOutput) -> GuardrailResult:
"""Custom validation function returning GuardrailResult."""
if "error" in task_output.raw.lower():
return GuardrailResult(
success=False,
result=None,
error="Output contains errors"
)
if len(task_output.raw) < 10:
return GuardrailResult(
success=False,
result=None,
error="Output is too short"
)
return GuardrailResult(
success=True,
result=task_output,
error=""
)
# Function-based guardrail (Option 2: Using Tuple[bool, Any])
def validate_output_tuple(task_output: TaskOutput) -> Tuple[bool, Any]:
"""Custom validation function returning tuple."""
if "error" in task_output.raw.lower():
return False, "Output contains errors"
if len(task_output.raw) < 10:
return False, "Output is too short"
return True, task_output
task = Task(
description="Write a professional email",
expected_output="A well-formatted email",
agent=agent,
guardrail=validate_output, # Function-based guardrail
max_retries=3 # Retry up to 3 times if guardrail fails
)
# LLM-based guardrail
task = Task(
description="Generate marketing copy",
expected_output="Professional marketing content",
agent=agent,
guardrail="Ensure the content is professional, engaging, and free of errors", # String description
max_retries=2
)
```
#### Agent-Level Guardrails
```python
# Agent guardrails apply to ALL outputs from that agent
# Option 1: Using GuardrailResult
def validate_professional_tone(task_output: TaskOutput) -> GuardrailResult:
"""Ensure professional tone in all agent responses."""
content = task_output.raw.lower()
casual_words = ['yo', 'dude', 'awesome', 'cool']
for word in casual_words:
if word in content:
return GuardrailResult(
success=False,
result=None,
error=f"Unprofessional language detected: {word}"
)
return GuardrailResult(
success=True,
result=task_output,
error=""
)
# Option 2: Using Tuple[bool, Any]
def validate_professional_tone_tuple(task_output: TaskOutput) -> Tuple[bool, Any]:
"""Ensure professional tone in all agent responses."""
content = task_output.raw.lower()
casual_words = ['yo', 'dude', 'awesome', 'cool']
for word in casual_words:
if word in content:
return False, f"Unprofessional language detected: {word}"
return True, task_output
# Agent with function-based guardrail
agent = Agent(
name="BusinessWriter",
instructions="You are a professional business writer",
guardrail=validate_professional_tone, # Function guardrail
max_guardrail_retries=3
)
# Agent with LLM-based guardrail
agent = Agent(
name="ContentWriter",
instructions="You are a content writer",
guardrail="Ensure all responses are professional, accurate, and appropriate for business use", # String guardrail
max_guardrail_retries=2
)
```
### Multi-Agent Workflow
```python
workflow = PraisonAIAgents(
agents=[agent1, agent2],
tasks=[task1, task2],
process="sequential", # or "hierarchical", "parallel"
verbose=True,
manager_agent=manager_agent # For hierarchical process
)
result = workflow.start()
```
### Async Support
All major components support async execution:
```python
result = await workflow.astart()
result = await agent.aexecute(task)
```
## Key Dependencies
- **Core**: `pydantic`, `rich`, `openai`, `mcp`
- **Memory**: `chromadb`, `mem0ai`
- **Knowledge**: `markitdown`, `chonkie`
- **LLM**: `litellm` for unified provider access
- **API**: `fastapi`, `uvicorn` for server capabilities
## Error Handling
- Global error logging via `error_logs` list
- Callback system for real-time error reporting
- Context length exception handling with automatic retry
- Graceful degradation for optional dependencies
## Testing Strategy
The project uses example-driven testing with 100+ test files in `tests/` directory. Each test file demonstrates specific usage patterns and serves as both test and documentation. Run individual examples to test functionality rather than using a formal test runner.
Use conda activate praisonai-agents to activate the environment.
+63
View File
@@ -0,0 +1,63 @@
"""
Streaming Example with Profiling
Key Points:
1. output="stream" preset enables streaming by default
2. stream=True in start() is redundant when using output="stream" (but doesn't hurt)
3. Profiler.enable() MUST be called before profiling works
4. Use Profiler.streaming() context manager for TTFT metrics
"""
from praisonai.profiler import Profiler, profile, profile_imports
# IMPORTANT: Enable profiler BEFORE any profiling operations
Profiler.enable()
# Profile imports
with profile_imports():
from praisonaiagents import Agent
@profile
def main():
agent = Agent(
instructions="You are a helpful assistant",
output="stream" # This already enables streaming
)
print("\nStreaming response:")
print("-" * 40)
# Use Profiler.streaming() to track TTFT (Time To First Token)
with Profiler.streaming("llm_stream") as tracker:
first_chunk = True
for chunk in agent.start("Write a short paragraph about the history of computing"):
if first_chunk:
tracker.first_token() # Mark TTFT
first_chunk = False
tracker.chunk() # Count chunks
print(chunk, end="", flush=True)
print("\n" + "-" * 40)
# Run with profiling blocks
with Profiler.block("full_workflow"):
with Profiler.block("setup"):
pass
with Profiler.block("execution"):
result = main()
with Profiler.block("cleanup"):
pass
# Generate report
Profiler.report()
# Show streaming-specific stats
streaming_records = Profiler.get_streaming_records()
if streaming_records:
print("\nStreaming Metrics:")
for record in streaming_records:
print(f" {record.name}: TTFT={record.ttft_ms:.2f}ms, Total={record.total_ms:.2f}ms, Chunks={record.chunk_count}")
stats = Profiler.get_statistics()
print(f"\nMedian execution time: {stats['p50']:.2f}ms")
@@ -1,98 +1,75 @@
#!/usr/bin/env python3
"""
Agent-level guardrails example.
This example demonstrates how to use guardrails at the Agent level,
This example demonstrates how to use guardrails at the Agent level
which will apply to all tasks executed by that agent.
"""
from typing import Tuple, Any
from praisonaiagents import Agent, TaskOutput
def validate_content_length(task_output: TaskOutput) -> Tuple[bool, Any]:
"""
Validate that task output content meets minimum length requirement.
Args:
task_output: The task output to validate
Returns:
Tuple of (success, result_or_error_message)
"""
if len(task_output.raw) < 50:
return False, "Content too short - must be at least 50 characters"
return True, task_output
def validate_professional_tone(task_output: TaskOutput) -> Tuple[bool, Any]:
"""
Validate that the content has a professional tone.
Args:
task_output: The task output to validate
Returns:
Tuple of (success, result_or_error_message)
"""
content = task_output.raw.lower()
unprofessional_words = ['yo', 'dude', 'awesome', 'cool', 'lol']
for word in unprofessional_words:
if word in content:
return False, f"Content contains unprofessional word: '{word}'"
return True, task_output
def main():
"""Demonstrate Agent-level guardrails with function-based and LLM-based validation."""
print("=== Agent Guardrail Examples ===\n")
# Example 1: Function-based guardrail
print("1. Function-based guardrail (content length validation):")
agent1 = Agent(
name="ContentWriter",
instructions="You are a professional content writer who creates detailed responses",
guardrail=validate_content_length,
max_guardrail_retries=2
name="ContentWriter"
instructions="You are a professional content writer who creates detailed responses"
guardrails=validate_content_length
)
try:
result1 = agent1.start("Write a brief welcome message")
print(f"Result: {result1}\n")
except Exception as e:
print(f"Error: {e}\n")
# Example 2: LLM-based guardrail (string description)
print("2. LLM-based guardrail (professional tone validation):")
agent2 = Agent(
name="BusinessWriter",
instructions="You are a business communication expert",
guardrail="Ensure the content is professional, formal, and suitable for business communication. No casual language or slang.",
max_guardrail_retries=3
instructions="You are a business communication expert"
guardrails="Ensure the content is professional, formal, and suitable for business communication. No casual language or slang."
)
try:
result2 = agent2.start("Write a welcome message for new employees")
print(f"Result: {result2}\n")
except Exception as e:
print(f"Error: {e}\n")
# Example 3: Multiple agents with different guardrails
print("3. Professional tone function-based guardrail:")
agent3 = Agent(
name="ProfessionalWriter",
instructions="Write professional business content",
guardrail=validate_professional_tone,
max_guardrail_retries=2
name="ProfessionalWriter"
instructions="Write professional business content"
guardrails=validate_professional_tone
)
try:
result3 = agent3.start("Write a casual greeting message")
print(f"Result: {result3}\n")
except Exception as e:
print(f"Error: {e}\n")
print("=== Agent Guardrails Demonstration Complete ===")
if __name__ == "__main__":
main()
@@ -21,7 +21,7 @@ article_agent = Agent(
goal="Fetch the user's favorite morning article",
tools=[fetch_favorite_article],
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
verbose=True
output="verbose"
)
news_agent = Agent(
@@ -30,7 +30,7 @@ news_agent = Agent(
goal="Search for trending news in Kenya",
tools=[search_trending_kenya],
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
verbose=True
output="verbose"
)
twitter_agent = Agent(
@@ -39,7 +39,7 @@ twitter_agent = Agent(
goal="Fetch the latest Twitter feed",
tools=[fetch_twitter_feed],
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
verbose=True
output="verbose"
)
aggregator = Agent(
@@ -47,7 +47,7 @@ aggregator = Agent(
role="Result Aggregator",
goal="Aggregate and summarize all results",
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
verbose=True
output="verbose"
)
# Tasks for each agent
@@ -92,7 +92,7 @@ async def main():
agents=[article_agent, news_agent, twitter_agent, aggregator],
tasks=[article_task, news_task, twitter_task, aggregate_task],
process="workflow",
verbose=True
output="verbose"
)
results = await workflow.astart(dict_output=True)
+2 -2
View File
@@ -5,8 +5,8 @@ async def main():
agent = Agent(
instructions="You are a helpful assistant",
llm="gemini/gemini-1.5-flash-8b",
self_reflect=True,
verbose=True
reflection=True,
output="verbose"
)
# Use achat instead of start/chat for async operation
@@ -10,7 +10,7 @@ import os
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
llm_config = {
"model": "gpt-5-nano", # Changed from Gemini to gpt-5-nano for better tool support
"model": "gpt-4o-mini", # Changed from Gemini to gpt-5-nano for better tool support
"temperature": 0.7,
"response_format": {
"type": "text"
@@ -79,7 +79,7 @@ async def run_parallel_searches():
backstory="Expert in web search and information retrieval. You have access to the tavily_search tool to search the web.",
tools=[tavily_search],
llm=llm_config,
verbose=True
output="verbose"
)
# Create summary agent
+1 -1
View File
@@ -52,7 +52,7 @@ agents = AutoAgents(
tools=[evaluate, get_stock_price],
process="sequential",
llm="gemini/gemini-2.5-flash-lite-preview-06-17",
self_reflect=False,
reflection=False,
verbose=False,
max_agents=3 # Maximum number of agents to create
)
+3 -2
View File
@@ -5,8 +5,9 @@ def get_weather(city: str) -> str:
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano",
tools=[get_weather]
llm="gpt-4o-mini",
tools=[get_weather],
output="status"
)
agent.start("What is the weather in Tokyo?")
+2 -13
View File
@@ -1,14 +1,3 @@
#!/usr/bin/env python3
from praisonaiagents import Agent
print("Creating agent...")
agent = Agent(
instructions="You are a helpful assistant"
)
print("Starting agent...")
result = agent.start("Why is the sky blue?")
print("Agent completed successfully!")
print(f"Result: {result}")
agent = Agent(instructions="You are a helpful assistant")
result = agent.start("Why is the sky blue?")
@@ -1,6 +1,6 @@
# PraisonAI Agents - Real Execution Benchmark
**Generated:** 2025-12-18 14:43:52
**Generated:** 2026-01-13 06:07:28
**Model:** gpt-4o-mini
**Iterations:** 3
**Prompt:** "What is 2+2? Reply with just the number."
@@ -9,18 +9,18 @@
| Framework | Method | Avg Time | Relative |
|-----------|--------|----------|----------|
| **PraisonAI** | `agent.start()` | **0.45s** | **1.00x (fastest)** |
| PraisonAI (LiteLLM) | `agent.start()` | 0.55s | 1.22x |
| CrewAI | `crew.kickoff()` | 0.58s | 1.28x |
| Agno | `agent.run()` | 0.92s | 2.05x |
| **PraisonAI (LiteLLM)** | `agent.start()` | **0.55s** | **1.00x (fastest)** |
| PraisonAI | `agent.start()` | 0.64s | 1.15x |
| CrewAI | `crew.kickoff()` | 0.95s | 1.71x |
| Agno | `agent.run()` | 1.05s | 1.90x |
## Package Versions
| Package | Version |
|---------|--------|
| PraisonAI | 0.1.5 |
| Agno | 2.3.14 |
| CrewAI | 1.6.1 |
| PraisonAI | 0.11.7 |
| Agno | 2.3.25 |
| CrewAI | 1.8.0 |
## How to Reproduce
@@ -1,6 +1,6 @@
# PraisonAI Agents - Real-World Execution Benchmark
**Generated:** 2025-12-18 14:33:49
**Generated:** 2026-01-13 14:42:59
**Model:** gpt-4o-mini
**Iterations:** 3 per test
@@ -8,60 +8,60 @@
| Test | PraisonAI (avg) | Agno (avg) | Difference |
|------|-----------------|------------|------------|
| Single Agent | 2.04s | 3.18s | PraisonAI 1.56x faster |
| 2 Agents | 2.49s | 20.49s | PraisonAI 8.21x faster |
| 3 Agents | 6.52s | 13.97s | PraisonAI 2.14x faster |
| Single Agent | 2.46s | 2.92s | PraisonAI 1.19x faster |
| 2 Agents | 3.21s | 19.39s | PraisonAI 6.05x faster |
| 3 Agents | 8.26s | 15.01s | PraisonAI 1.82x faster |
## Detailed Results
### praisonai_single
- Average: 2.04s
- Min: 1.95s
- Max: 2.19s
- Std Dev: 0.13s
- Times: ['2.19s', '1.95s', '2.00s']
- Average: 2.46s
- Min: 1.93s
- Max: 2.90s
- Std Dev: 0.49s
- Times: ['1.93s', '2.55s', '2.90s']
### agno_single
- Average: 3.18s
- Min: 3.00s
- Max: 3.51s
- Std Dev: 0.28s
- Times: ['3.51s', '3.00s', '3.04s']
- Average: 2.92s
- Min: 2.85s
- Max: 2.97s
- Std Dev: 0.06s
- Times: ['2.97s', '2.85s', '2.94s']
### praisonai_two_agents
- Average: 2.49s
- Min: 2.22s
- Max: 2.65s
- Std Dev: 0.24s
- Times: ['2.65s', '2.22s', '2.62s']
- Average: 3.21s
- Min: 2.80s
- Max: 3.67s
- Std Dev: 0.44s
- Times: ['3.67s', '2.80s', '3.15s']
### agno_two_agents
- Average: 20.49s
- Min: 9.96s
- Max: 35.05s
- Std Dev: 13.02s
- Times: ['16.46s', '9.96s', '35.05s']
- Average: 19.39s
- Min: 10.62s
- Max: 26.06s
- Std Dev: 7.93s
- Times: ['26.06s', '10.62s', '21.50s']
### praisonai_three_agents
- Average: 6.52s
- Min: 5.62s
- Max: 7.39s
- Std Dev: 0.88s
- Times: ['5.62s', '6.54s', '7.39s']
- Average: 8.26s
- Min: 6.44s
- Max: 11.88s
- Std Dev: 3.13s
- Times: ['6.47s', '6.44s', '11.88s']
### agno_three_agents
- Average: 13.97s
- Min: 11.69s
- Max: 15.32s
- Std Dev: 1.99s
- Times: ['14.91s', '11.69s', '15.32s']
- Average: 15.01s
- Min: 14.46s
- Max: 15.90s
- Std Dev: 0.78s
- Times: ['15.90s', '14.46s', '14.68s']
## Package Versions
| Package | Version |
|---------|--------|
| PraisonAI | 0.1.5 |
| Agno | 2.3.14 |
| PraisonAI | 0.11.22 |
| Agno | 2.3.25 |
## How to Reproduce
@@ -52,12 +52,11 @@ def benchmark_praisonai(model, iterations, prompt):
agent = Agent(
name="Calculator",
instructions="You are a helpful assistant. Be very brief.",
llm=model,
verbose=False
llm=model
)
start = time.perf_counter()
response = agent.start(prompt)
response = agent.start(prompt, output="silent")
elapsed = time.perf_counter() - start
times.append(elapsed)
@@ -80,12 +79,11 @@ def benchmark_praisonai_litellm(model, iterations, prompt):
agent = Agent(
name="Calculator",
instructions="You are a helpful assistant. Be very brief.",
llm=f"openai/{model}",
verbose=False
llm=f"openai/{model}"
)
start = time.perf_counter()
response = agent.start(prompt)
response = agent.start(prompt, output="silent")
elapsed = time.perf_counter() - start
times.append(elapsed)
@@ -103,12 +103,11 @@ def benchmark_praisonai_single(iterations: int = 3) -> ExecutionResult:
name="Assistant",
instructions="You are a helpful assistant. Be very brief.",
llm="gpt-4o-mini",
tools=[get_weather],
verbose=False
tools=[get_weather]
)
start = time.perf_counter()
response = agent.start("What's the weather in NYC? Reply in one sentence.")
response = agent.start("What's the weather in NYC? Reply in one sentence.", output="silent")
elapsed = time.perf_counter() - start
result.times.append(elapsed)
@@ -132,8 +131,7 @@ def benchmark_praisonai_two_agents(iterations: int = 3) -> ExecutionResult:
goal="Gather weather information",
instructions="Get weather data and pass to reporter. Be brief.",
llm="gpt-4o-mini",
tools=[get_weather],
verbose=False
tools=[get_weather]
)
reporter = Agent(
@@ -141,18 +139,16 @@ def benchmark_praisonai_two_agents(iterations: int = 3) -> ExecutionResult:
role="News Reporter",
goal="Create weather report",
instructions="Create a one-sentence weather summary.",
llm="gpt-4o-mini",
verbose=False
llm="gpt-4o-mini"
)
agents = Agents(
agents=[researcher, reporter],
process="sequential",
verbose=False
process="sequential"
)
start = time.perf_counter()
response = agents.start("Get NYC weather and create a brief report.")
response = agents.start("Get NYC weather and create a brief report.", output="silent")
elapsed = time.perf_counter() - start
result.times.append(elapsed)
@@ -176,8 +172,7 @@ def benchmark_praisonai_three_agents(iterations: int = 3) -> ExecutionResult:
goal="Get weather data",
instructions="Fetch weather information. Be brief.",
llm="gpt-4o-mini",
tools=[get_weather],
verbose=False
tools=[get_weather]
)
time_agent = Agent(
@@ -186,8 +181,7 @@ def benchmark_praisonai_three_agents(iterations: int = 3) -> ExecutionResult:
goal="Get time information",
instructions="Fetch timezone information. Be brief.",
llm="gpt-4o-mini",
tools=[get_time],
verbose=False
tools=[get_time]
)
summarizer = Agent(
@@ -195,18 +189,16 @@ def benchmark_praisonai_three_agents(iterations: int = 3) -> ExecutionResult:
role="Summary Writer",
goal="Combine information",
instructions="Create a one-sentence summary combining weather and time.",
llm="gpt-4o-mini",
verbose=False
llm="gpt-4o-mini"
)
agents = Agents(
agents=[weather_agent, time_agent, summarizer],
process="sequential",
verbose=False
process="sequential"
)
start = time.perf_counter()
response = agents.start("Get NYC weather and EST time, then summarize.")
response = agents.start("Get NYC weather and EST time, then summarize.", output="silent")
elapsed = time.perf_counter() - start
result.times.append(elapsed)
+1 -1
View File
@@ -1,5 +1,5 @@
from praisonaiagents import ContextAgent
agent = ContextAgent(llm="gpt-5-nano", auto_analyze=False)
agent = ContextAgent(llm="gpt-4o-mini", auto_analyze=False)
agent.start("https://github.com/MervinPraison/PraisonAI/ Need to add Authentication")
+1 -1
View File
@@ -14,7 +14,7 @@ def test_agent_direct():
agent = Agent(
instructions="""You are a helpful assistant that can break down complex problems.
Use the available tools when relevant to perform step-by-step analysis.""",
llm="gpt-5-nano",
llm="gpt-4o-mini",
tools=MCP("npx -y @modelcontextprotocol/server-sequential-thinking")
)
@@ -0,0 +1,23 @@
"""Advanced memory example - with config and overrides."""
from praisonaiagents import Agent, MemoryConfig
# With full config
agent = Agent(
instructions="You are a helpful assistant with memory.",
memory=MemoryConfig(
backend="redis",
user_id="user123",
session_id="session456",
auto_memory=True,
),
)
# With array [preset, overrides]
agent_override = Agent(
instructions="You are a helpful assistant.",
memory=["redis", {"user_id": "custom_user"}],
)
if __name__ == "__main__":
response = agent.chat("Remember that my favorite color is blue.")
print(response)
@@ -0,0 +1,24 @@
"""Basic memory example - minimal usage."""
from praisonaiagents import Agent
# Simple enable (uses default file-based memory)
agent = Agent(
instructions="You are a helpful assistant with memory.",
memory=True,
)
# With preset
agent_redis = Agent(
instructions="You are a helpful assistant.",
memory="redis", # Uses redis preset
)
# With URL
agent_postgres = Agent(
instructions="You are a helpful assistant.",
memory="postgresql://localhost/mydb", # URL auto-detected
)
if __name__ == "__main__":
response = agent.chat("Remember that my favorite color is blue.")
print(response)
@@ -0,0 +1,13 @@
"""Basic output and execution example."""
from praisonaiagents import Agent
# Simple preset usage
agent = Agent(
instructions="You are a helpful assistant.",
output="verbose", # Preset: verbose output
execution="thorough", # Preset: thorough execution
)
if __name__ == "__main__":
response = agent.chat("What is 2+2?")
print(response)
@@ -0,0 +1,22 @@
"""Basic workflow example with consolidated params."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
# Create agents
writer = Agent(instructions="You are a content writer.")
editor = Agent(instructions="You are an editor.")
# Create workflow with consolidated params
workflow = Workflow(
name="Content Pipeline",
steps=[
WorkflowStep(name="write", agent=writer, action="Write about {{topic}}"),
WorkflowStep(name="edit", agent=editor, action="Edit the content", context=["write"]),
],
output="verbose",
planning=True,
)
if __name__ == "__main__":
result = workflow.run(variables={"topic": "AI agents"})
print(result)
@@ -14,8 +14,8 @@ llm_config = {
agent = Agent(
instructions="You are a helpful assistant. Be concise and clear.",
llm=llm_config,
verbose=True,
self_reflect=True,
output="verbose",
reflection=True,
max_reflect=2,
min_reflect=1
)
@@ -7,8 +7,7 @@ def validate_content(data):
agent = Agent(
instructions="You are a writer",
guardrail=validate_content,
max_guardrail_retries=1
guardrails=validate_content
)
agent.start("Write a welcome message with 5 words")
@@ -12,7 +12,7 @@ agent = Agent(
task = Task(
description="Write a welcome message",
guardrail=validate_content,
guardrails=validate_content,
agent=agent
)
+2 -2
View File
@@ -62,7 +62,7 @@ def main():
description="Write a professional email to a client about project completion",
expected_output="A well-formatted professional email",
agent=agent,
guardrail=email_validator, # Function-based guardrail
guardrails=email_validator, # Function-based guardrail
max_retries=2
)
@@ -110,7 +110,7 @@ Project Team""",
description="Write a marketing email for a new product launch",
expected_output="Engaging marketing content",
agent=agent,
guardrail="Ensure the content is professional, engaging, includes a clear call-to-action, and is free of errors",
guardrails="Ensure the content is professional, engaging, includes a clear call-to-action, and is free of errors",
max_retries=3
)
+1 -1
View File
@@ -9,7 +9,7 @@ agent = Agent(
goal="Search for information from multiple sources",
backstory="I am an AI assistant that can search YouTube and Wikipedia.",
tools=[YouTubeSearchTool, WikipediaAPIWrapper],
self_reflect=False
reflection=False
)
# Create tasks to demonstrate both tools
+2 -2
View File
@@ -32,9 +32,9 @@ agent = Agent(
instructions="You are a helpful Assistant specialized in scientific explanations. "
"Provide clear, accurate, and engaging responses.",
llm=llm_config, # Pass the detailed configuration
verbose=True, # Enable detailed output
output="verbose", # Enable detailed output
markdown=True, # Format responses in markdown
self_reflect=True, # Enable self-reflection
reflection=True, # Enable self-reflection
max_reflect=3, # Maximum reflection iterations
min_reflect=1 # Minimum reflection iterations
)
+1 -1
View File
@@ -3,7 +3,7 @@ from praisonaiagents import Agent, MCP
agent = Agent(
instructions="""You are a helpful assistant that can check stock prices and perform other tasks.
Use the available tools when relevant to answer user questions.""",
llm="gpt-5-nano",
llm="gpt-4o-mini",
tools = MCP("/Users/praison/miniconda3/envs/mcp/bin/python /Users/praison/stockprice/app.py")
)
@@ -71,7 +71,7 @@ def main():
tools=[mongodb_tools],
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# 2. Knowledge Curator Agent - manages knowledge base
@@ -85,7 +85,7 @@ def main():
knowledge_config=mongodb_knowledge_config,
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# 3. Business Analyst Agent - analyzes data and provides insights
@@ -99,7 +99,7 @@ def main():
tools=[mongodb_tools],
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# 4. Customer Service Agent - handles customer interactions
@@ -114,7 +114,7 @@ def main():
tools=[mongodb_tools],
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create comprehensive business tasks
@@ -55,11 +55,9 @@ def main():
retrieve information from a comprehensive MongoDB knowledge base. You excel
at finding relevant information, synthesizing knowledge from multiple sources,
and providing accurate, context-aware responses.""",
knowledge_config=mongodb_knowledge_config,
knowledge=[os.path.join(os.path.dirname(__file__), "llms.md")],
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create a research assistant agent
@@ -72,8 +70,7 @@ def main():
knowledge base. You ensure information is accurate, well-structured,
and properly categorized.""",
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create tasks for knowledge management
@@ -128,7 +125,7 @@ def main():
agents=[research_agent, knowledge_agent],
tasks=knowledge_tasks,
memory=True,
verbose=True
output="verbose"
)
# Execute the knowledge management pipeline
@@ -59,7 +59,7 @@ def main():
knowledge=[os.path.join(os.path.dirname(__file__), "llms.md")],
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create a research assistant agent
@@ -73,7 +73,7 @@ def main():
and properly categorized.""",
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create tasks for knowledge management
+2 -2
View File
@@ -3,7 +3,7 @@ from praisonaiagents.memory import Memory
from praisonaiagents.agent import ContextAgent
import pymongo
context_agent = ContextAgent(llm="gpt-5-nano", auto_analyze=False)
context_agent = ContextAgent(llm="gpt-4o-mini", auto_analyze=False)
context_output = context_agent.start("https://github.com/MervinPraison/PraisonAI/ Need to add Authentication")
@@ -25,7 +25,7 @@ implementation_agent = Agent(
goal="Implement authentication features based on project requirements",
backstory="Expert software implementer specializing in authentication systems, security features, and seamless integration with existing codebases",
memory=True,
llm="gpt-5-nano",
llm="gpt-4o-mini",
)
implementation_task = Task(
@@ -50,7 +50,7 @@ def main():
retrieve relevant information from your persistent memory store.""",
memory=True,
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create research tasks
@@ -38,7 +38,7 @@ def main():
for data management and retrieval.""",
tools=[mongodb_tools],
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create a Data Analysis Agent
@@ -51,7 +51,7 @@ def main():
identify patterns and trends in the stored information.""",
tools=[mongodb_tools],
verbose=True,
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
# Create tasks for MongoDB operations
+7
View File
@@ -0,0 +1,7 @@
from praisonaiagents import Agent, Agents
research_agent = Agent(instructions="Research about AI")
summarise_agent = Agent(instructions="Summarise research agent's findings")
agents = Agents(agents=[research_agent, summarise_agent])
response = agents.start()
+1 -1
View File
@@ -2,6 +2,6 @@ from praisonaiagents import Agent
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
agent.start("Why sky is Blue?")
+1 -1
View File
@@ -2,7 +2,7 @@ from praisonaiagents import Agent
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
agent.start("Why sky is Blue?")
agent.start("What was my previous question?")
+1 -1
View File
@@ -3,7 +3,7 @@ import asyncio
agent = Agent(
instructions="You are a helpful assistant",
llm="gpt-5-nano"
llm="gpt-4o-mini"
)
agent.run("Why sea is Blue?")
+1 -1
View File
@@ -22,7 +22,7 @@ def multiply(a: int, b: int) -> int:
agent = Agent(
instructions="You are a helpful assistant. You can use the tools provided to you to help the user.",
llm="gpt-5-nano",
llm="gpt-4o-mini",
tools=[get_stock_price, multiply]
)
+1 -2
View File
@@ -14,8 +14,7 @@ task2 = Task(description="Write a short article about meditation benefits", agen
agents = Agents(
agents=[researcher, writer],
tasks=[task1, task2],
planning=True,
auto_approve_plan=True # Auto-approve the generated plan
planning=True
)
agents.start()
+1 -1
View File
@@ -22,7 +22,7 @@ def multiply(a: int, b: int) -> int:
agent = Agent(
instructions="You are a helpful assistant. You can use the tools provided to you to help the user.",
llm="gpt-5-nano",
llm="gpt-4o-mini",
tools=[get_stock_price, multiply]
)
+203 -166
View File
@@ -5,6 +5,29 @@ This module uses lazy loading to minimize import time and memory usage.
Heavy dependencies like litellm are only loaded when actually needed.
"""
# =============================================================================
# NAMESPACE PACKAGE GUARD
# =============================================================================
# Detect if we're loaded as a namespace package (which indicates stale artifacts
# in site-packages). This happens when there's a praisonaiagents/ directory in
# site-packages without an __init__.py file.
#
# Root cause: Partial uninstall or version mismatch leaves directories that
# Python's PathFinder treats as namespace packages, shadowing the real package.
# =============================================================================
if __file__ is None:
import warnings as _ns_warnings
_ns_warnings.warn(
"praisonaiagents is loaded as a namespace package, which indicates "
"stale artifacts in site-packages. This will cause import errors. "
"Fix: Remove the stale directory with:\n"
" rm -rf $(python -c \"import site; print(site.getsitepackages()[0])\")/praisonaiagents/\n"
"Then reinstall: pip install praisonaiagents",
ImportWarning,
stacklevel=1
)
del _ns_warnings
# Apply warning patch BEFORE any imports to intercept warnings at the source
from . import _warning_patch # noqa: F401
@@ -25,6 +48,14 @@ from .tools.registry import get_registry, register_tool, get_tool, ToolRegistry
from .db import db
from .obs import obs
# Sub-packages for organized imports (pa.config, pa.tools, etc.)
# These enable: import praisonaiagents as pa; pa.config.MemoryConfig
from . import config
from . import tools
from . import memory
from . import workflows
# Note: knowledge and mcp are lazy-loaded via __getattr__ due to heavy deps
# Workflows - lightweight module
from .workflows import (
Workflow, WorkflowStep, WorkflowContext, StepResult,
@@ -68,7 +99,18 @@ from .main import (
)
# Module-level caches for lazy-loaded classes
_lazy_cache = {}
# Using threading.local() ensures thread-safe access to cached values
import threading
_lazy_cache_local = threading.local()
def _get_lazy_cache():
"""Get thread-local lazy cache dict. Thread-safe for concurrent access."""
if not hasattr(_lazy_cache_local, 'cache'):
_lazy_cache_local.cache = {}
return _lazy_cache_local.cache
# Backward-compatible alias (module-level access still works, now thread-safe)
_lazy_cache = {} # Kept for compatibility, but prefer _get_lazy_cache()
# Flags for optional modules
_mcp_available = None
@@ -177,6 +219,13 @@ def __getattr__(name):
_lazy_cache["PraisonAIAgents"] = Agents # Also cache alias
return Agents
elif name == "PraisonAIAgents":
import warnings
warnings.warn(
"PraisonAIAgents is deprecated, use Agents instead. "
"Example: from praisonaiagents import Agents",
DeprecationWarning,
stacklevel=2
)
from .agents.agents import Agents
_lazy_cache["Agents"] = Agents
_lazy_cache[name] = Agents
@@ -435,6 +484,51 @@ def __getattr__(name):
_lazy_cache[name] = ContextManager
return ContextManager
# =========================================================================
# Sub-package fallback: delegate to sub-packages for additional symbols
# This enables: from praisonaiagents import duckduckgo, FileMemory, etc.
# =========================================================================
# Try tools sub-package (110+ tool functions)
try:
from . import tools as _tools_module
if hasattr(_tools_module, name):
result = getattr(_tools_module, name)
_lazy_cache[name] = result
return result
except (ImportError, AttributeError):
pass
# Try memory sub-package (FileMemory, RulesManager, etc.)
try:
from . import memory as _memory_module
if hasattr(_memory_module, name):
result = getattr(_memory_module, name)
_lazy_cache[name] = result
return result
except (ImportError, AttributeError):
pass
# Try config sub-package (already handled above, but catch any stragglers)
try:
from . import config as _config_module
if hasattr(_config_module, name):
result = getattr(_config_module, name)
_lazy_cache[name] = result
return result
except (ImportError, AttributeError):
pass
# Try workflows sub-package (Pipeline, Route, etc. - already imported, catch aliases)
try:
from . import workflows as _workflows_module
if hasattr(_workflows_module, name):
result = getattr(_workflows_module, name)
_lazy_cache[name] = result
return result
except (ImportError, AttributeError):
pass
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -469,174 +563,117 @@ def _init_telemetry():
_init_telemetry()
def warmup(include_litellm: bool = False, include_openai: bool = True) -> dict:
"""
Pre-import heavy dependencies to reduce first-call latency.
NOTE: For default OpenAI usage (llm="gpt-4o-mini"), warmup is NOT needed.
The default path uses the native OpenAI SDK which is fast (~100ms import).
Warmup is only beneficial when using LiteLLM backend, which is triggered by:
- Using "/" in model name (e.g., llm="openai/gpt-4o-mini")
- Passing a dict config (e.g., llm={"model": "gpt-4o-mini"})
- Using base_url parameter
Args:
include_litellm: Pre-import LiteLLM (~2-3s). Only needed for multi-provider support.
include_openai: Pre-import OpenAI SDK (~100ms). Default path, usually fast.
Returns:
dict: Timing information for each component warmed up
Example:
# For LiteLLM multi-provider usage:
from praisonaiagents import warmup
warmup(include_litellm=True) # Pre-load LiteLLM
agent = Agent(llm="anthropic/claude-3-sonnet") # Now faster
# For default OpenAI usage, no warmup needed:
agent = Agent(llm="gpt-4o-mini") # Already fast!
"""
import time
timings = {}
if include_openai:
start = time.perf_counter()
try:
import openai
timings['openai'] = (time.perf_counter() - start) * 1000
except ImportError:
timings['openai'] = -1 # Not available
if include_litellm:
start = time.perf_counter()
try:
import litellm
# Also configure litellm to avoid first-call overhead
litellm.telemetry = False
litellm.set_verbose = False
litellm.drop_params = True
litellm.modify_params = True
timings['litellm'] = (time.perf_counter() - start) * 1000
except ImportError:
timings['litellm'] = -1 # Not available
return timings
# ============================================================================
# PUBLIC API: __all__ (controls IDE autocomplete and `from X import *`)
# ============================================================================
# DESIGN: Keep __all__ minimal for clean IDE experience.
# All 186+ symbols are still accessible via __getattr__ for backwards compat.
# Organized imports available via sub-packages: config, tools, memory, workflows
# ============================================================================
__all__ = [
# Core classes (lazy loaded)
# Core classes - the essentials
'Agent',
'ImageAgent',
'ContextAgent',
'create_context_agent',
'PraisonAIAgents',
'Agents',
'Tools',
'Task',
# Plugin system
'BaseTool',
'ToolResult',
'ToolValidationError',
'validate_tool',
# Tool essentials
'tool',
'FunctionTool',
'ToolRegistry',
'get_registry',
'register_tool',
'get_tool',
'TaskOutput',
'ReflectionOutput',
'AutoAgents',
'AutoRagAgent',
'AutoRagConfig',
'RagRetrievalPolicy',
'Session',
'Memory',
'db',
'obs',
'display_interaction',
'display_self_reflection',
'display_instruction',
'display_tool_call',
'display_error',
'display_generating',
'clean_triple_backticks',
'error_logs',
'register_display_callback',
'sync_display_callbacks',
'async_display_callbacks',
'Knowledge',
'Chunking',
'GuardrailResult',
'LLMGuardrail',
'Handoff',
'handoff',
'handoff_filters',
'RECOMMENDED_PROMPT_PREFIX',
'prompt_with_handoff_instructions',
'HandoffConfig',
'HandoffResult',
'HandoffInputData',
'ContextPolicy',
'HandoffError',
'HandoffCycleError',
'HandoffDepthError',
'HandoffTimeoutError',
'get_telemetry',
'enable_telemetry',
'disable_telemetry',
'enable_performance_mode',
'disable_performance_mode',
'cleanup_telemetry_resources',
'MinimalTelemetry',
'TelemetryCollector',
'DeepResearchAgent',
'DeepResearchResponse',
'Citation',
'ReasoningStep',
'WebSearchCall',
'CodeExecutionStep',
'MCPCall',
'FileSearchCall',
'Provider',
'QueryRewriterAgent',
'RewriteStrategy',
'RewriteResult',
'PromptExpanderAgent',
'ExpandStrategy',
'ExpandResult',
# Workflows
'Workflow',
'WorkflowStep',
'WorkflowContext',
'StepResult',
'Route',
'Parallel',
'Loop',
'Repeat',
'route',
'parallel',
'loop',
'repeat',
'Pipeline',
# MCP
'MCP',
# Flow display
'FlowDisplay',
'track_workflow',
# FastContext
'FastContext',
'FastContextResult',
'FileMatch',
'LineRange',
# Agent Skills
'SkillManager',
'SkillProperties',
'SkillMetadata',
'SkillLoader',
# Planning
'Plan',
'PlanStep',
'TodoList',
'TodoItem',
'PlanStorage',
'PlanningAgent',
'ApprovalCallback',
'READ_ONLY_TOOLS',
'RESTRICTED_TOOLS',
# UI
'AGUI',
'A2A',
# RAG
'RAG',
'RAGConfig',
'RAGResult',
'RAGCitation',
# Feature Configs (agent-centric API)
'MemoryConfig',
'KnowledgeConfig',
'PlanningConfig',
'ReflectionConfig',
'GuardrailConfig',
'WebConfig',
'OutputConfig',
'ExecutionConfig',
'TemplateConfig',
'CachingConfig',
'HooksConfig',
'SkillsConfig',
'AutonomyConfig',
'MemoryBackend',
'ChunkingStrategy',
'GuardrailAction',
'WebSearchProvider',
'OutputPreset',
'ExecutionPreset',
'AutonomyLevel',
# Multi-Agent Feature Configs
'MultiAgentHooksConfig',
'MultiAgentOutputConfig',
'MultiAgentExecutionConfig',
'MultiAgentPlanningConfig',
'MultiAgentMemoryConfig',
# Context Management
'ManagerConfig',
'ContextManager',
# Parameter Resolution (agent-centric API)
'resolve',
'ArrayMode',
'resolve_guardrails',
'resolve_guardrail_policies',
# Presets (agent-centric API)
'GUARDRAIL_PRESETS',
'KNOWLEDGE_PRESETS',
# Parse Utilities
'is_policy_string',
'parse_policy_string',
'Tools',
# Sub-packages for organized imports
# Usage: import praisonaiagents as pa; pa.config.MemoryConfig
'config',
'tools',
'memory',
'workflows',
]
def __dir__():
"""
Return clean list for dir() - matches __all__ plus standard attributes.
This keeps IDE autocomplete clean while preserving full backwards
compatibility via __getattr__ for all 186+ legacy exports.
"""
return list(__all__) + [
# Standard module attributes
'__name__', '__doc__', '__file__', '__path__', '__package__',
'__loader__', '__spec__', '__cached__', '__builtins__',
]
# ============================================================================
# BACKWARDS COMPATIBILITY: Legacy __all__ items (for reference)
# ============================================================================
# All items below are still importable via __getattr__ but NOT in autocomplete:
# - ImageAgent, ContextAgent, create_context_agent, PraisonAIAgents
# - BaseTool, ToolResult, ToolValidationError, validate_tool, FunctionTool
# - ToolRegistry, get_registry, register_tool, get_tool
# - TaskOutput, ReflectionOutput, AutoAgents, AutoRagAgent, AutoRagConfig
# - Session, Memory, db, obs, Knowledge, Chunking
# - GuardrailResult, LLMGuardrail, Handoff, handoff, handoff_filters
# - MemoryConfig, KnowledgeConfig, PlanningConfig, OutputConfig, etc.
# - Workflow, WorkflowStep, Route, Parallel, Loop, Repeat, Pipeline, etc.
# - MCP, FlowDisplay, track_workflow, FastContext, etc.
# - Plan, PlanStep, TodoList, PlanningAgent, ApprovalCallback, etc.
# - RAG, RAGConfig, RAGResult, AGUI, A2A, etc.
# - All telemetry, display, and utility functions
# ============================================================================
@@ -0,0 +1,49 @@
"""
Resolver helper functions for consolidated parameters.
These helpers wrap the canonical resolver for specific parameter types,
handling special cases like callable validators for guardrails.
"""
from typing import Any, Type
from .config.param_resolver import resolve, ArrayMode
from .config.presets import GUARDRAIL_PRESETS
def resolve_guardrails(value: Any, config_class: Type) -> Any:
"""
Resolve guardrails parameter.
Handles special case of callable validators which have highest precedence.
Args:
value: The guardrails parameter value
config_class: GuardrailConfig class
Returns:
Resolved config, callable, or string
"""
# Handle None
if value is None:
return None
# Handle False (disabled)
if value is False:
return None
# Handle callable (highest precedence after None check)
# This includes functions, lambdas, and callable objects
if callable(value) and not isinstance(value, type):
return value
# Use canonical resolver for everything else
return resolve(
value=value,
param_name="guardrails",
config_class=config_class,
presets=GUARDRAIL_PRESETS,
array_mode=ArrayMode.PRESET_OVERRIDE,
string_mode="llm_prompt",
default=None,
)
@@ -30,6 +30,13 @@ from .prompt_expander_agent import (
ExpandStrategy,
ExpandResult
)
from .protocols import (
AgentProtocol,
RunnableAgentProtocol,
ToolAwareAgentProtocol,
MemoryAwareAgentProtocol,
FullAgentProtocol,
)
__all__ = [
'Agent',
@@ -64,5 +71,11 @@ __all__ = [
'RewriteResult',
'PromptExpanderAgent',
'ExpandStrategy',
'ExpandResult'
'ExpandResult',
# Protocols
'AgentProtocol',
'RunnableAgentProtocol',
'ToolAwareAgentProtocol',
'MemoryAwareAgentProtocol',
'FullAgentProtocol',
]
File diff suppressed because it is too large. Load diff
@@ -434,8 +434,7 @@ This report contains all agent interactions and outputs from a complete ContextA
Provide comprehensive analysis that follows the PRD template principles and enables
AI assistants to implement features that perfectly match existing codebase patterns.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Analyze this gitingest codebase digest following PRD template methodology:
@@ -515,8 +514,7 @@ codebase style and architecture following PRD template principles."""
role="Expert Manual Codebase Analysis Specialist",
goal="Perform comprehensive manual codebase analysis following PRD methodology",
instructions="""Analyze the codebase samples following PRD template methodology for complete understanding.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Format comprehensive sample
@@ -566,8 +564,7 @@ Analyze following PRD principles to extract patterns, conventions, and architect
6. Design pattern implementations
7. Code complexity metrics
8. API and interface patterns""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Perform AST analysis on Python files
@@ -624,8 +621,7 @@ Extract comprehensive patterns that follow PRD template principles for implement
For each pattern, provide the pattern name, where it's used, and how to replicate it
following PRD template principles.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get representative code samples
@@ -674,8 +670,7 @@ patterns and best practices for first-try success."""
goal="Analyze testing patterns for comprehensive validation framework design",
instructions="""Analyze testing patterns to understand validation approaches and create
comprehensive test frameworks following PRD methodology.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get test files
@@ -801,8 +796,7 @@ Extract testing patterns for validation framework creation following PRD princip
Confidence level for one-pass implementation
Generate PRPs following this EXACT structure for first-try implementation success.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Generate a comprehensive Product Requirements Prompt (PRP) following the EXACT PRD template structure:
@@ -850,8 +844,7 @@ on the first try following PRD template principles."""
6. CODE QUALITY: Complexity analysis, maintainability
7. DOCUMENTATION VALIDATION: Documentation completeness
8. DEPENDENCY VALIDATION: Dependency analysis and security""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Analyze existing validation patterns
@@ -897,8 +890,7 @@ following PRD template principles."""
instructions="""Compile all available documentation following PRD methodology including:
README files, API documentation, setup guides, architecture docs, and any other
relevant documentation that provides context for implementation.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get documentation files
@@ -943,8 +935,7 @@ following PRD template principles."""
instructions="""Analyze integration points following PRD methodology including:
APIs, databases, external services, configuration points, and any other
integration requirements that affect implementation.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Get configuration and dependency files
@@ -1004,8 +995,7 @@ following PRD template principles."""
8. DOCUMENTATION UPDATES: Documentation to create/update
9. INTEGRATION STEPS: How to integrate with existing systems
10. VALIDATION CHECKPOINTS: Validation steps at each phase""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Create detailed implementation blueprint following PRD methodology:
@@ -1302,8 +1292,7 @@ Every agent interaction has been saved for full audit trail and reproducibility.
GOAL: [extracted implementation goal]
Be precise and extract only what is explicitly mentioned or clearly implied.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Parse this user input to extract codebase and goal:
@@ -1536,8 +1525,7 @@ Note: Detailed function/class metadata not available due to content access limit
5. Documentation topics
Make the output easy for a file selection agent to understand which files contain what functionality.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
structure_text = basic_structure.get('structure', '')
@@ -1770,8 +1758,7 @@ Focus on creating clear, structured metadata that will help with intelligent fil
["README.md", "src/auth/login.py", "config/settings.py", ...]
Maximum 50 files for efficient analysis.""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
# Prepare enhanced structure information
@@ -1923,8 +1910,7 @@ Maximum 50 files.""".format(goal=goal)
8. EXAMPLES: Similar features that can guide {goal} implementation
Since these files were pre-selected for relevance, provide deep analysis of how each contributes to implementing: {goal}""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
prompt = f"""Analyze these carefully selected repository files for implementing: {goal}
@@ -2024,8 +2010,7 @@ Since these files were pre-selected for relevance, explain how each contributes
- Success criteria for {goal}
Focus everything on successfully implementing: {goal}""",
llm=self.llm if hasattr(self, 'llm') else "gpt-5-nano",
verbose=getattr(self, 'verbose', True)
llm=self.llm if hasattr(self, 'llm') else "gpt-4o-mini",
)
chunk_info = ""
@@ -2303,13 +2288,13 @@ def create_context_agent(llm: Optional[Union[str, Any]] = None, **kwargs) -> Con
Factory function to create a ContextAgent following Context Engineering and PRD methodology.
Args:
llm: Language model to use (e.g., "gpt-5-nano", "claude-3-haiku")
llm: Language model to use (e.g., "gpt-4o-mini", "claude-3-haiku")
**kwargs: Additional arguments to pass to ContextAgent constructor
Returns:
ContextAgent: Configured ContextAgent for comprehensive context generation following PRD principles
"""
if llm is None:
llm = "gpt-5-nano"
llm = "gpt-4o-mini"
return ContextAgent(llm=llm, **kwargs)
@@ -17,7 +17,7 @@ Supported Expansion Strategies:
Example:
from praisonaiagents import PromptExpanderAgent, ExpandStrategy
agent = PromptExpanderAgent(verbose=True)
agent = PromptExpanderAgent()
# Basic expansion
result = agent.expand("write a movie script in 3 lines")
@@ -29,7 +29,7 @@ Example:
# With tools for context gathering
from praisonaiagents.tools import internet_search
agent = PromptExpanderAgent(tools=[internet_search], verbose=True)
agent = PromptExpanderAgent(tools=[internet_search])
result = agent.expand("latest AI developments")
"""
@@ -73,13 +73,12 @@ class PromptExpanderAgent:
Attributes:
name: Name of the agent
model: LLM model to use for expansion
verbose: Whether to print detailed logs
model: LLM model to use for expansion (alias for llm=)
temperature: Temperature for LLM generation (higher = more creative)
tools: Optional tools for context gathering
Example:
agent = PromptExpanderAgent(model="gpt-4o-mini", verbose=True)
agent = PromptExpanderAgent(model="gpt-4o-mini")
result = agent.expand("write a poem", strategy=ExpandStrategy.CREATIVE)
print(result.expanded_prompt)
"""
@@ -230,8 +229,7 @@ Expanded prompt:"""
backstory="You are an expert at understanding user intent and transforming brief requests into comprehensive, detailed prompts.",
tools=self.tools,
llm=self.model,
verbose=self.verbose,
markdown=False
output={"verbose": self.verbose, "markdown": False}
)
return self._agent
@@ -0,0 +1,151 @@
"""
Agent Protocol Definitions.
Provides Protocol interfaces that define the minimal contract for agent implementations.
This enables:
- Mocking agents in tests without real LLM calls
- Creating custom agent implementations
- Type checking with static analyzers
These protocols are lightweight and have zero performance impact.
"""
from typing import Protocol, runtime_checkable, Optional, Any, Dict, List
@runtime_checkable
class AgentProtocol(Protocol):
"""
Minimal Protocol for agent implementations.
This defines the essential interface that any agent must provide.
It enables proper mocking and testing without real LLM dependencies.
Example:
```python
# Create a mock agent for testing
class MockAgent:
@property
def name(self) -> str:
return "TestAgent"
def chat(self, prompt: str, **kwargs) -> str:
return "Mock response"
async def achat(self, prompt: str, **kwargs) -> str:
return "Async mock response"
# Use in tests
agent: AgentProtocol = MockAgent()
result = agent.chat("Hello")
```
"""
@property
def name(self) -> str:
"""Agent's name identifier."""
...
def chat(self, prompt: str, **kwargs) -> str:
"""
Synchronous chat with the agent.
Args:
prompt: The user prompt or message
**kwargs: Additional optional parameters (temperature, tools, etc.)
Returns:
The agent's response as a string
"""
...
async def achat(self, prompt: str, **kwargs) -> str:
"""
Asynchronous chat with the agent.
Args:
prompt: The user prompt or message
**kwargs: Additional optional parameters (temperature, tools, etc.)
Returns:
The agent's response as a string
"""
...
@runtime_checkable
class RunnableAgentProtocol(AgentProtocol, Protocol):
"""
Extended Protocol for agents that support run/start methods.
This extends AgentProtocol with the run/start interface used
by the Agent class for task execution.
"""
def run(self, prompt: str, **kwargs) -> str:
"""Run the agent with a prompt (alias for chat in most cases)."""
...
def start(self, prompt: str, **kwargs) -> str:
"""Start the agent with a prompt."""
...
async def arun(self, prompt: str, **kwargs) -> str:
"""Async run the agent with a prompt."""
...
async def astart(self, prompt: str, **kwargs) -> str:
"""Async start the agent with a prompt."""
...
@runtime_checkable
class ToolAwareAgentProtocol(AgentProtocol, Protocol):
"""
Protocol for agents that support tools.
This extends AgentProtocol with tool-related properties.
"""
@property
def tools(self) -> List[Any]:
"""List of tools available to the agent."""
...
@runtime_checkable
class MemoryAwareAgentProtocol(AgentProtocol, Protocol):
"""
Protocol for agents that support memory.
This extends AgentProtocol with memory-related properties.
"""
@property
def chat_history(self) -> List[Dict[str, Any]]:
"""The agent's conversation history."""
...
def clear_history(self) -> None:
"""Clear the agent's conversation history."""
...
# Composite protocol for fully-featured agents
@runtime_checkable
class FullAgentProtocol(RunnableAgentProtocol, ToolAwareAgentProtocol, MemoryAwareAgentProtocol, Protocol):
"""
Complete Protocol for full-featured agents.
This combines all agent protocol features for agents that support
the full interface (chat, run, tools, memory).
"""
pass
__all__ = [
'AgentProtocol',
'RunnableAgentProtocol',
'ToolAwareAgentProtocol',
'MemoryAwareAgentProtocol',
'FullAgentProtocol',
]
@@ -15,7 +15,7 @@ Supported Rewriting Strategies:
Example:
from praisonaiagents import QueryRewriterAgent, RewriteStrategy
agent = QueryRewriterAgent(verbose=True)
agent = QueryRewriterAgent()
# Basic rewriting
result = agent.rewrite("AI trends")
@@ -34,7 +34,7 @@ Example:
# With search tools for context-aware rewriting
from praisonaiagents.tools import internet_search
agent = QueryRewriterAgent(tools=[internet_search], verbose=True)
agent = QueryRewriterAgent(tools=[internet_search])
result = agent.rewrite("latest AI developments") # Searches first, then rewrites
"""
@@ -96,13 +96,12 @@ class QueryRewriterAgent:
Attributes:
name: Name of the agent
model: LLM model to use for rewriting
verbose: Whether to print detailed logs
model: LLM model to use for rewriting (alias for llm=)
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)
agent = QueryRewriterAgent(model="gpt-4o-mini")
result = agent.rewrite("ML best practices", strategy=RewriteStrategy.MULTI_QUERY)
for query in result.rewritten_queries:
print(query)
@@ -288,8 +287,7 @@ Improved version:"""
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
output={"verbose": self.verbose, "markdown": False}
)
return self._agent
@@ -44,7 +44,7 @@ class RouterAgent(Agent):
# Initialize model router
self.model_router = model_router or ModelRouter()
self.routing_strategy = routing_strategy
self.fallback_model = fallback_model or os.getenv('OPENAI_MODEL_NAME', 'gpt-5-nano')
self.fallback_model = fallback_model or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o-mini')
# Process models configuration
self.available_models = self._process_models_config(models)
@@ -65,6 +65,52 @@ def process_video(video_path: str, seconds_per_frame=2):
video.release()
return base64_frames
def get_multimodal_message(text_prompt: str, images: list) -> list:
"""
Build multimodal message content for LLM with text and images.
DRY helper - replaces duplicate _get_multimodal_message in aexecute_task/execute_task.
Args:
text_prompt: The text content of the message
images: List of image paths (local or URL)
Returns:
List of content items for multimodal LLM message
"""
content = [{"type": "text", "text": text_prompt}]
for img in images:
# If local file path for a valid image
if os.path.exists(img):
ext = os.path.splitext(img)[1].lower()
# If it's a .mp4, convert to frames
if ext == ".mp4":
frames = process_video(img, seconds_per_frame=1)
content.append({"type": "text", "text": "These are frames from the video."})
for f in frames:
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpg;base64,{f}"}
})
else:
encoded = encode_file_to_base64(img)
content.append({
"type": "image_url",
"image_url": {
"url": f"data:image/{ext.lstrip('.')};base64,{encoded}"
}
})
else:
# Treat as a remote URL
content.append({
"type": "image_url",
"image_url": {"url": img}
})
return content
def process_task_context(context_item, verbose=0, user_id=None):
"""
Process a single context item for task execution.
@@ -142,6 +188,13 @@ class Agents:
output: Optional[Any] = None, # Union[str, MultiAgentOutputConfig]
execution: Optional[Any] = None, # Union[str, MultiAgentExecutionConfig]
hooks: Optional[Any] = None, # MultiAgentHooksConfig
# Additional consolidated params for feature parity with Agent
autonomy: Optional[Any] = None, # Union[bool, AutonomyConfig] - agent autonomy
knowledge: Optional[Any] = None, # Union[bool, List[str], KnowledgeConfig] - RAG
guardrails: Optional[Any] = None, # Union[bool, Callable, GuardrailConfig] - validation
web: Optional[Any] = None, # Union[bool, WebConfig] - web search/fetch
reflection: Optional[Any] = None, # Union[bool, ReflectionConfig] - self-reflection
caching: Optional[Any] = None, # Union[bool, CachingConfig] - caching
):
"""
Initialize PraisonAIAgents with consolidated feature parameters.
@@ -159,7 +212,19 @@ class Agents:
output: Output configuration (str | MultiAgentOutputConfig)
execution: Execution configuration (str | MultiAgentExecutionConfig)
hooks: Hooks configuration (MultiAgentHooksConfig)
autonomy: Autonomy configuration (bool | AutonomyConfig)
knowledge: Knowledge/RAG configuration (bool | List[str] | KnowledgeConfig)
guardrails: Guardrails configuration (bool | Callable | GuardrailConfig)
web: Web search/fetch configuration (bool | WebConfig)
reflection: Self-reflection configuration (bool | ReflectionConfig)
"""
# Store new params for propagation to agents
self._autonomy = autonomy
self._knowledge = knowledge
self._guardrails = guardrails
self._web = web
self._reflection = reflection
self._caching = caching
# ─────────────────────────────────────────────────────────────────────
# Extract values from consolidated params using UNIFIED CANONICAL resolver
# Precedence: Instance > Config > Dict > Array > String > Bool > Default
@@ -344,7 +409,7 @@ class Agents:
self.variables = variables if variables else {}
# Check for manager_llm in environment variable if not provided
self.manager_llm = manager_llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-5-nano')
self.manager_llm = manager_llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o-mini')
# Set logger level based on verbose
if _verbose >= 5:
@@ -447,10 +512,16 @@ class Agents:
if self.shared_memory:
for task in tasks:
if not task.memory:
task.memory = self.shared_memory
logger.info(f"Assigned shared memory to task {task.id}")
# Telemetry
try:
from ..telemetry import get_telemetry
self._telemetry = get_telemetry()
except (ImportError, AttributeError):
self._telemetry = None
def add_task(self, task):
task_id = self.task_id_counter
task.id = task_id
@@ -584,40 +655,9 @@ Context:
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
if task.images:
def _get_multimodal_message(text_prompt, images):
content = [{"type": "text", "text": text_prompt}]
for img in images:
# If local file path for a valid image
if os.path.exists(img):
ext = os.path.splitext(img)[1].lower()
# If it's a .mp4, convert to frames
if ext == ".mp4":
frames = process_video(img, seconds_per_frame=1)
content.append({"type": "text", "text": "These are frames from the video."})
for f in frames:
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpg;base64,{f}"}
})
else:
encoded = encode_file_to_base64(img)
content.append({
"type": "image_url",
"image_url": {
"url": f"data:image/{ext.lstrip('.')};base64,{encoded}"
}
})
else:
# Treat as a remote URL
content.append({
"type": "image_url",
"image_url": {"url": img}
})
return content
# Use shared multimodal helper (DRY - defined at module level)
agent_output = await executor_agent.achat(
_get_multimodal_message(task_prompt, task.images),
get_multimodal_message(task_prompt, task.images),
tools=tools,
output_json=task.output_json,
output_pydantic=task.output_pydantic,
@@ -802,13 +842,17 @@ Context:
await loop.run_in_executor(None, self.run_task, task_id)
async def astart(self, content=None, return_dict=False, **kwargs):
"""Async version of start method
"""Async version of start method.
Args:
content: Optional content to add to all tasks' context
return_dict: If True, returns the full results dictionary instead of only the final response
**kwargs: Additional arguments
"""
# Track execution via telemetry
if hasattr(self, '_telemetry') and self._telemetry:
self._telemetry.track_agent_execution(self.name, success=True, async_mode=True)
if content:
# Add content to context of all tasks
for task in self.tasks.values():
@@ -942,40 +986,9 @@ Context:
logger.debug(f"Starting execution of task {task_id} with prompt:\n{task_prompt}")
if task.images:
def _get_multimodal_message(text_prompt, images):
content = [{"type": "text", "text": text_prompt}]
for img in images:
# If local file path for a valid image
if os.path.exists(img):
ext = os.path.splitext(img)[1].lower()
# If it's a .mp4, convert to frames
if ext == ".mp4":
frames = process_video(img, seconds_per_frame=1)
content.append({"type": "text", "text": "These are frames from the video."})
for f in frames:
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpg;base64,{f}"}
})
else:
encoded = encode_file_to_base64(img)
content.append({
"type": "image_url",
"image_url": {
"url": f"data:image/{ext.lstrip('.')};base64,{encoded}"
}
})
else:
# Treat as a remote URL
content.append({
"type": "image_url",
"image_url": {"url": img}
})
return content
# Use shared multimodal helper (DRY - defined at module level)
agent_output = executor_agent.chat(
_get_multimodal_message(task_prompt, task.images),
get_multimodal_message(task_prompt, task.images),
tools=task.tools,
output_json=task.output_json,
output_pydantic=task.output_pydantic,
@@ -1174,30 +1187,147 @@ Context:
return str(agent[0])
return None
def start(self, content=None, return_dict=False, **kwargs):
"""Start agent execution with optional content and config
def start(self, content=None, return_dict=False, output=None, **kwargs):
"""Start agent execution with verbose output (beginner-friendly).
Shows Rich panels with workflow progress when in TTY. Use .run() for
silent execution in production/scripts.
Args:
content: Optional content to add to all tasks' context
return_dict: If True, returns the full results dictionary instead of only the final response
return_dict: If True, returns the full results dictionary
output: Output preset - "silent", "verbose", "normal", etc.
Default in TTY: "verbose" (shows progress)
Default non-TTY: "silent"
**kwargs: Additional arguments
Example:
```python
# Interactive - shows Rich panels
agents = Agents(agents=[agent1, agent2])
result = agents.start() # Verbose output by default
# Force silent mode
result = agents.start(output="silent")
```
"""
# Track execution via telemetry
if hasattr(self, '_telemetry') and self._telemetry:
self._telemetry.track_agent_execution(self.name, success=True)
import sys
from ..main import PRAISON_COLORS
# Determine if we're in an interactive TTY
is_tty = sys.stdout.isatty()
# Resolve output mode (TTY-aware)
if output is None:
# Default: verbose in TTY (beginner-friendly), silent otherwise
# Note: Don't check self.verbose here - start() is for interactive use
show_verbose = is_tty
elif output == "silent":
show_verbose = False
elif output in ("verbose", "debug", "normal"):
show_verbose = True
else:
show_verbose = is_tty
# Add content to context if provided
if content:
# Add content to context of all tasks
for task in self.tasks.values():
if isinstance(content, (str, list)):
# If context is empty, initialize it
if not task.context:
task.context = []
# Add content to context
task.context.append(content)
# Planning Mode: Create plan and todo list before execution
if self.planning:
self._run_with_planning()
# ─────────────────────────────────────────────────────────────
# Verbose Mode: Show Rich panels for multi-agent workflow
# ─────────────────────────────────────────────────────────────
if show_verbose and is_tty:
from rich.panel import Panel
from rich.text import Text
console = Console()
import time as time_module
# Show workflow overview panel
agent_names = " → ".join([a.name for a in self.agents])
workflow_info = f"[bold {PRAISON_COLORS['metrics']}]Process:[/] {self.process}\n"
workflow_info += f"[bold {PRAISON_COLORS['metrics']}]Agents:[/] {agent_names}"
console.print(Panel(
workflow_info,
title="[bold]Multi-Agent Workflow[/]",
border_style=PRAISON_COLORS["agent"],
padding=(1, 2)
))
console.print()
# Execute tasks with verbose output
total_agents = len(self.agents)
workflow_start_time = time_module.time()
for idx, (task_id, task) in enumerate(self.tasks.items(), 1):
agent = task.agent
agent_name = agent.name if agent else "Unknown"
agent_model = getattr(agent, 'llm', 'gpt-4o-mini') if agent else "unknown"
# Show agent task panel with model info
task_desc = task.description[:100] + "..." if len(task.description) > 100 else task.description
panel_content = f"[bold {PRAISON_COLORS['task_text']}]📋 Task:[/] {task_desc}\n"
panel_content += f"[dim]🤖 Model: {agent_model}[/dim]"
console.print(Panel.fit(
panel_content,
title=f"[bold]Agent [{idx}/{total_agents}]: {agent_name}[/]",
border_style=PRAISON_COLORS["task"]
))
# Execute with timing and status
start_time = time_module.time()
# Show working spinner
with console.status(
f"[bold yellow]Working...[/] {agent_name} generating response...",
spinner="dots",
spinner_style="yellow"
):
# Run the task
if self.planning:
self._run_with_planning()
break # Planning mode handles all tasks
else:
self.run_task(task_id)
elapsed = time_module.time() - start_time
# Show response panel - FULL response, no truncation
result = self.get_task_result(task_id)
if result:
response_text = str(result.raw)
# No truncation - show full response in verbose mode
from rich.markdown import Markdown
console.print(Panel(
Markdown(response_text),
title=f"[bold]Agent [{idx}/{total_agents}] Complete ({elapsed:.1f}s)[/]",
border_style=PRAISON_COLORS["response"],
padding=(1, 2)
))
console.print()
# Workflow summary panel
total_elapsed = time_module.time() - workflow_start_time
console.print(Panel.fit(
f"[bold green]Total Time:[/] {total_elapsed:.1f}s\n"
f"[bold green]Agents Run:[/] {total_agents}/{total_agents}",
title="[bold]✅ Workflow Complete[/]",
border_style="green"
))
console.print()
else:
# Run tasks as before
self.run_all_tasks()
# Silent mode: Run tasks without display
if self.planning:
self._run_with_planning()
else:
self.run_all_tasks()
# Auto-display token metrics if any agent has metrics=True
metrics_enabled = any(getattr(agent, 'metrics', False) for agent in self.agents)
@@ -1205,10 +1335,8 @@ Context:
try:
self.display_token_usage()
except (ImportError, AttributeError) as e:
# Token tracking not available or not properly configured
logging.debug(f"Could not auto-display token usage: {e}")
except Exception as e:
# Log unexpected errors for debugging
logging.debug(f"Unexpected error in token metrics display: {e}")
# Get results
@@ -1219,7 +1347,6 @@ Context:
# By default, return only the final agent's response
if not return_dict:
# Get the last task (assuming sequential processing)
task_ids = list(self.tasks.keys())
if task_ids:
last_task_id = task_ids[-1]
@@ -1227,12 +1354,21 @@ Context:
if last_result:
return last_result.raw
# Return full results dict if return_dict is True or if no final result was found
return results
def run(self, content=None, return_dict=False, **kwargs):
"""Alias for start() method to provide consistent API with Agent class"""
return self.start(content=content, return_dict=return_dict, **kwargs)
"""Run agents silently (production use).
Unlike .start() which shows verbose output, .run() executes silently
for programmatic/production use.
Args:
content: Optional content to add to all tasks' context
return_dict: If True, returns the full results dictionary
**kwargs: Additional arguments
"""
# Always run silently - no verbose output
return self.start(content=content, return_dict=return_dict, output="silent", **kwargs)
def set_state(self, key: str, value: Any) -> None:
"""Set a state value"""
@@ -2172,7 +2308,7 @@ Context:
# Inherit from original task if available
memory=original_task.memory if original_task else None,
callback=original_task.callback if original_task else None,
guardrail=original_task.guardrail if original_task else None,
guardrails=original_task.guardrail if original_task else None,
max_retries=original_task.max_retries if original_task else 3,
output_json=original_task.output_json if original_task else None,
output_pydantic=original_task.output_pydantic if original_task else None,
@@ -74,6 +74,17 @@ class AutoAgents(Agents):
api_key: Optional[str] = None,
max_agents: int = 3, # Maximum number of agents
autonomy: Optional[Any] = None, # Union[bool, dict, AutonomyConfig] - Enable autonomy for all agents
# ============================================================
# CONSOLIDATED PARAMS (new SDK contract - take precedence)
# ============================================================
output: Optional[Any] = None, # Union[str, OutputConfig] - overrides verbose/markdown
reflection: Optional[Any] = None, # Union[bool, ReflectionConfig] - overrides self_reflect/max_reflect/min_reflect/reflect_llm
caching: Optional[Any] = None, # Union[bool, CachingConfig] - overrides cache
knowledge: Optional[Any] = None, # Union[bool, List[str], KnowledgeConfig] - overrides knowledge_sources/embedder_config
execution: Optional[Any] = None, # Union[str, ExecutionConfig] - overrides max_iter
guardrails: Optional[Any] = None, # Union[bool, Callable, GuardrailConfig]
web: Optional[Any] = None, # Union[bool, WebConfig]
hooks: Optional[Any] = None, # HooksConfig
):
"""Initialize AutoAgents with configuration for automatic agent and task creation."""
if max_agents < 1:
@@ -92,7 +103,7 @@ class AutoAgents(Agents):
self.self_reflect = self_reflect
self.max_reflect = max_reflect
self.min_reflect = min_reflect
self.llm = llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-5-nano')
self.llm = llm or os.getenv('OPENAI_MODEL_NAME', 'gpt-4o-mini')
self.function_calling_llm = function_calling_llm
self.code_execution_mode = code_execution_mode
self.embedder_config = embedder_config
@@ -112,6 +123,16 @@ class AutoAgents(Agents):
self.api_key = api_key
self.autonomy = autonomy # Store autonomy config for agents
# Store consolidated params (new SDK contract - take precedence over legacy)
self._output = output
self._reflection = reflection
self._caching = caching
self._knowledge = knowledge
self._execution = execution
self._guardrails = guardrails
self._web = web
self._hooks = hooks
# Display initial instruction
if self.verbose:
display_instruction(f"🎯 Main Task: {self.instructions}")
@@ -129,14 +150,21 @@ class AutoAgents(Agents):
self._display_agents_and_tasks(agents, tasks)
# Initialize parent class with generated agents and tasks
# Use consolidated output= instead of legacy verbose=
super().__init__(
agents=agents,
tasks=tasks,
verbose=verbose,
completion_checker=completion_checker,
max_retries=max_retries,
process=process,
manager_llm=manager_llm or self.llm
manager_llm=manager_llm or self.llm,
output=self._output, # Consolidated output param
execution=self._execution,
hooks=self._hooks,
memory=self.memory,
reflection=self._reflection,
caching=self._caching,
guardrails=self._guardrails,
web=self._web,
autonomy=self.autonomy,
)
def _display_agents_and_tasks(self, agents: List[Agent], tasks: List[Task]):
@@ -431,38 +459,33 @@ DO NOT use strings for tasks. Each task MUST be a complete object with all four
agent_tools = self._assign_tools_to_agent(agent_config)
# Create the agent with all parameters
# Consolidated params take precedence over legacy params
# Use consolidated knowledge if provided, else fall back to legacy knowledge_sources
effective_knowledge = self._knowledge if self._knowledge is not None else self.knowledge_sources
agent = Agent(
name=agent_config.name,
role=agent_config.role,
goal=agent_config.goal,
backstory=agent_config.backstory,
tools=agent_tools, # Use assigned tools
verbose=self.verbose >= 1,
allow_code_execution=self.allow_code_execution,
memory=self.memory,
markdown=self.markdown,
self_reflect=self.self_reflect,
max_reflect=self.max_reflect,
min_reflect=self.min_reflect,
llm=self.llm,
function_calling_llm=self.function_calling_llm,
llm=self.llm, # Consolidated LLM param
code_execution_mode=self.code_execution_mode,
embedder_config=self.embedder_config,
knowledge=self.knowledge_sources,
use_system_prompt=self.use_system_prompt,
cache=self.cache,
allow_delegation=self.allow_delegation,
step_callback=self.step_callback,
system_template=self.system_template,
prompt_template=self.prompt_template,
response_template=self.response_template,
max_rpm=self.max_rpm,
max_execution_time=self.max_execution_time,
max_iter=self.max_iter,
reflect_llm=self.reflect_llm,
base_url=self.base_url,
api_key=self.api_key,
autonomy=self.autonomy # Pass autonomy config to agents
# Consolidated params (new SDK contract)
output=self._output, # Overrides verbose/markdown
reflection=self._reflection, # Overrides self_reflect/max_reflect/min_reflect/reflect_llm
caching=self._caching, # Overrides cache
knowledge=effective_knowledge, # Overrides knowledge_sources/embedder_config
execution=self._execution, # Overrides max_iter
guardrails=self._guardrails,
web=self._web,
hooks=self._hooks,
autonomy=self.autonomy,
)
agents.append(agent)
@@ -376,7 +376,7 @@ class SubagentDelegator:
return result
async def _create_agent(self, profile: AgentProfile, task: DelegationTask) -> Any:
"""Create an agent from profile."""
"""Create an agent from profile using consolidated params."""
if self.agent_factory:
return self.agent_factory(profile.name)
@@ -387,14 +387,17 @@ class SubagentDelegator:
# Filter tools based on profile
tools = self._get_tools_for_profile(profile)
# Use consolidated params (protocol-compliant)
# output='silent' replaces verbose=False
# execution={max_iter: N} replaces max_iter=N
agent = Agent(
name=profile.name,
role=profile.name.title(),
goal=task.objective,
backstory=profile.system_prompt,
tools=tools,
verbose=False,
max_iter=min(task.max_steps, profile.max_steps),
output='silent',
execution={'max_iter': min(task.max_steps, profile.max_steps)},
)
return agent
@@ -13,10 +13,35 @@ from typing import Dict, Set, Optional, Callable, Any, Literal, List
from functools import wraps
from contextvars import ContextVar
from dataclasses import dataclass, field
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from rich.prompt import Confirm
# Lazy import for rich components
_rich_console = None
_rich_panel = None
_rich_confirm = None
def _get_rich_console():
"""Lazy import rich Console."""
global _rich_console
if _rich_console is None:
from rich.console import Console
_rich_console = Console
return _rich_console
def _get_rich_panel():
"""Lazy import rich Panel."""
global _rich_panel
if _rich_panel is None:
from rich.panel import Panel
_rich_panel = Panel
return _rich_panel
def _get_rich_confirm():
"""Lazy import rich Confirm."""
global _rich_confirm
if _rich_confirm is None:
from rich.prompt import Confirm
_rich_confirm = Confirm
return _rich_confirm
# Global registries for approval requirements
APPROVAL_REQUIRED_TOOLS: Set[str] = set()
@@ -308,6 +333,10 @@ def console_approval_callback(function_name: str, arguments: Dict[str, Any], ris
Displays tool information and prompts user for approval via console.
"""
Console = _get_rich_console()
Panel = _get_rich_panel()
Confirm = _get_rich_confirm()
console = Console()
# Create risk level styling
Loaded 100 of 475 files, more files were not shown because too many files have changed in this diff. Show more