mirror of
https://github.com/MervinPraison/PraisonAI.git
synced 2026-11-10 03:31:28 -10:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5f4feae62 | ||
|
|
8fa9a69f84 | ||
|
|
8293d5b106 | ||
|
|
a2d6e6b889 | ||
|
|
17b7a6aa90 | ||
|
|
1513d729ba |
No files matched your search
@@ -1,51 +0,0 @@
|
||||
# PraisonAI Environment Variables
|
||||
# Copy this file to .env and update with your actual values
|
||||
|
||||
# === Required ===
|
||||
OPENAI_API_KEY=sk-... # OpenAI key for LLM calls. Get yours at https://platform.openai.com
|
||||
|
||||
# === Required for Claw web-search tool ===
|
||||
TAVILY_API_KEY=tvly-... # Get yours at https://app.tavily.com (free tier available)
|
||||
|
||||
# === Optional: Claw dashboard security ===
|
||||
PRAISONAI_ALLOW_LOCAL_TOOLS=0 # Set to 1 to enable local shell tools (security risk)
|
||||
|
||||
# === Optional: Alternative LLM Providers ===
|
||||
ANTHROPIC_API_KEY=sk-ant-... # Anthropic Claude models
|
||||
GOOGLE_API_KEY=... # Google Gemini models
|
||||
GROQ_API_KEY=gsk_... # Groq (fast inference)
|
||||
COHERE_API_KEY=... # Cohere models
|
||||
AZURE_OPENAI_API_KEY=... # Azure OpenAI
|
||||
AZURE_OPENAI_ENDPOINT=... # Azure OpenAI endpoint
|
||||
|
||||
# === Optional: Memory backends ===
|
||||
MEM0_API_KEY=... # Mem0 memory service
|
||||
REDIS_URL=redis://localhost:6379 # Redis for state management
|
||||
|
||||
# === Optional: Observability ===
|
||||
LANGFUSE_SECRET_KEY=sk-lf-... # Langfuse tracing
|
||||
LANGFUSE_PUBLIC_KEY=pk-lf-... # Langfuse public key
|
||||
|
||||
# === Optional: Bot platforms ===
|
||||
TELEGRAM_BOT_TOKEN=... # Telegram bot token
|
||||
DISCORD_BOT_TOKEN=... # Discord bot token
|
||||
SLACK_BOT_TOKEN=xoxb-... # Slack bot token
|
||||
SLACK_APP_TOKEN=xapp-... # Slack app token
|
||||
WHATSAPP_ACCESS_TOKEN=... # WhatsApp bot access token
|
||||
WHATSAPP_PHONE_NUMBER_ID=... # WhatsApp phone number ID
|
||||
|
||||
# === Optional: Database ===
|
||||
DATABASE_URL=sqlite:///~/.praison/database.sqlite # Database connection string
|
||||
|
||||
# === Optional: Tool Security ===
|
||||
# ALLOWED_TOOLS=search,send_message # Whitelist specific tools to prevent name collisions
|
||||
# Useful in multi-environment setups with overlapping tool names
|
||||
# Leave unset to use all tools (with collision warnings)
|
||||
# Do NOT set to empty string: that's treated as configuration error
|
||||
# In CI, unknown tool names in the whitelist cause strict startup failure
|
||||
# HERMES_ONLY_TOOLS=search,send_message # (Deprecated) Backward compatibility alias for ALLOWED_TOOLS
|
||||
|
||||
# === Optional: Development ===
|
||||
LOGLEVEL=INFO # Logging level (DEBUG, INFO, WARNING, ERROR)
|
||||
CHAINLIT_AUTH_SECRET=... # Chainlit authentication secret
|
||||
DEBUG=false # Enable debug mode
|
||||
@@ -181,15 +181,12 @@ jobs:
|
||||
|
||||
- name: Fetch PR branch and Setup Remote
|
||||
if: github.event.issue.pull_request
|
||||
env:
|
||||
PR_BRANCH: ${{ steps.check_fork.outputs.pr_branch }}
|
||||
IS_FORK: ${{ steps.check_fork.outputs.is_fork }}
|
||||
run: |
|
||||
# Fetch PR head from base repo and put it into local branch
|
||||
git fetch origin pull/${{ github.event.issue.number }}/head:"${PR_BRANCH}"
|
||||
git fetch origin pull/${{ github.event.issue.number }}/head:${{ steps.check_fork.outputs.pr_branch }}
|
||||
|
||||
# If it's a fork, make origin point to local to trick claude-code-action's `git fetch origin <branch>`
|
||||
if [ "${IS_FORK}" = "true" ]; then
|
||||
if [ "${{ steps.check_fork.outputs.is_fork }}" == "true" ]; then
|
||||
git remote set-url origin file://$(pwd)
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
name: Cross-Repo Integration Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'src/praisonai/praisonai/integration/**'
|
||||
- 'src/praisonai/tests/integration/test_aiui_*'
|
||||
- 'src/praisonai/pyproject.toml'
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'src/praisonai/praisonai/integration/**'
|
||||
- 'src/praisonai/tests/integration/test_aiui_*'
|
||||
- 'src/praisonai/pyproject.toml'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
cross-repo-integration:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout PraisonAI
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: PraisonAI
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Checkout PraisonAIUI
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: MervinPraison/PraisonAIUI
|
||||
path: PraisonAIUI
|
||||
ref: main
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
# Install PraisonAI packages in development mode
|
||||
cd PraisonAI/src/praisonai-agents
|
||||
pip install -e .
|
||||
cd ../praisonai
|
||||
pip install -e ".[ui,dev]"
|
||||
# Install PraisonAIUI in development mode
|
||||
cd ../../../PraisonAIUI
|
||||
pip install -e .
|
||||
|
||||
- name: Verify versions
|
||||
run: |
|
||||
python -c "import praisonaiagents; print(f'praisonaiagents: {praisonaiagents.__version__}')"
|
||||
python -c "import praisonai; print(f'praisonai: {praisonai.__version__}')"
|
||||
python -c "import praisonaiui; print(f'praisonaiui: {praisonaiui.__version__}')"
|
||||
|
||||
- name: Run PraisonAI integration tests
|
||||
run: |
|
||||
cd PraisonAI/src/praisonai
|
||||
python -m pytest tests/integration/test_aiui_* -v --timeout=300
|
||||
|
||||
- name: Run PraisonAIUI integration tests
|
||||
run: |
|
||||
cd PraisonAIUI
|
||||
if [ -f tests/integration/test_agentic_roundtrip.py ]; then
|
||||
python -m pytest tests/integration/test_agentic_roundtrip.py -v --timeout=300
|
||||
fi
|
||||
if [ -f tests/test_feature_sdk_backends.py ]; then
|
||||
python -m pytest tests/test_feature_sdk_backends.py -v --timeout=300
|
||||
fi
|
||||
|
||||
- name: Test Pattern C CLI
|
||||
run: |
|
||||
cd PraisonAI/src/praisonai
|
||||
# Test that ui-gateway command exists
|
||||
python -m praisonai serve --help | grep ui-gateway
|
||||
|
||||
- name: Test public API exports
|
||||
run: |
|
||||
cd PraisonAI/src/praisonai
|
||||
python -c "from praisonai import run_integrated_gateway; print('✓ run_integrated_gateway imported')"
|
||||
python -c "from praisonai import configure_host; print('✓ configure_host imported')"
|
||||
|
||||
- name: Integration smoke test
|
||||
env:
|
||||
PRAISONAI_TEST_MODE: "1"
|
||||
PYTHONPATH: ${{ github.workspace }}/PraisonAI/src/praisonai:${{ github.workspace }}/PraisonAI/src/praisonai-agents:${{ github.workspace }}/PraisonAIUI
|
||||
run: |
|
||||
cd PraisonAI/src/praisonai
|
||||
python -c "
|
||||
import sys
|
||||
sys.path.insert(0, '.')
|
||||
from praisonai.integration.host_app import configure_host
|
||||
from praisonai import run_integrated_gateway
|
||||
print('✓ Integration imports successful')
|
||||
|
||||
# Test configure_host with new parameters
|
||||
try:
|
||||
configure_host(
|
||||
style='dashboard',
|
||||
context_paths=['AGENTS.md'],
|
||||
title='Test App'
|
||||
)
|
||||
print('✓ configure_host with new parameters works')
|
||||
except Exception as e:
|
||||
print(f'× configure_host failed: {e}')
|
||||
sys.exit(1)
|
||||
"
|
||||
|
||||
# Optional job with API key for agentic tests (if secret is available)
|
||||
agentic-integration:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
if: ${{ vars.RUN_AGENTIC_TESTS == 'true' }}
|
||||
needs: cross-repo-integration
|
||||
|
||||
steps:
|
||||
- name: Checkout PraisonAI
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: PraisonAI
|
||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Checkout PraisonAIUI
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: MervinPraison/PraisonAIUI
|
||||
path: PraisonAIUI
|
||||
ref: main
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
cd PraisonAI/src/praisonai-agents
|
||||
pip install -e .
|
||||
cd ../praisonai
|
||||
pip install -e ".[ui,dev]"
|
||||
cd ../../../PraisonAIUI
|
||||
pip install -e .
|
||||
|
||||
- name: Run agentic integration test
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
run: |
|
||||
cd PraisonAI/src/praisonai
|
||||
if [ -n "$OPENAI_API_KEY" ]; then
|
||||
python -m pytest tests/integration/test_aiui_host_agentic.py -v --timeout=600
|
||||
else
|
||||
echo "OPENAI_API_KEY not available, skipping agentic tests"
|
||||
fi
|
||||
@@ -29,6 +29,9 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
with:
|
||||
persist-credentials: false
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate GitHub App Token
|
||||
@@ -60,12 +63,10 @@ jobs:
|
||||
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
PRAISONAI_AUTO_APPROVE: "true"
|
||||
ISSUE_NUMBER_INPUT: ${{ inputs.issue_number }}
|
||||
ISSUE_NUMBER_EVENT: ${{ github.event.issue.number }}
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
export ISSUE_NUMBER="$ISSUE_NUMBER_INPUT"
|
||||
export ISSUE_NUMBER="${{ inputs.issue_number }}"
|
||||
else
|
||||
export ISSUE_NUMBER="$ISSUE_NUMBER_EVENT"
|
||||
export ISSUE_NUMBER="${{ github.event.issue.number }}"
|
||||
fi
|
||||
praisonai github triage --issue $ISSUE_NUMBER --agent-file .github/praisonai-issue-triage.yaml
|
||||
@@ -30,23 +30,22 @@ jobs:
|
||||
steps:
|
||||
- name: Determine checkout ref
|
||||
id: dest
|
||||
env:
|
||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
PR_NUMBER_INPUT: ${{ inputs.pr_number }}
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "issue_comment" ]; then
|
||||
echo "ref=refs/pull/$ISSUE_NUMBER/head" >> "$GITHUB_OUTPUT"
|
||||
echo "ref=refs/pull/${{ github.event.issue.number }}/head" >> "$GITHUB_OUTPUT"
|
||||
elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
echo "ref=refs/pull/$PR_NUMBER_INPUT/head" >> "$GITHUB_OUTPUT"
|
||||
echo "ref=refs/pull/${{ inputs.pr_number }}/head" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "ref=$PR_HEAD_SHA" >> "$GITHUB_OUTPUT"
|
||||
echo "ref=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
with:
|
||||
persist-credentials: false
|
||||
with:
|
||||
ref: ${{ steps.dest.outputs.ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
@@ -176,18 +176,6 @@ jobs:
|
||||
run: praisonai queue list
|
||||
continue-on-error: true
|
||||
|
||||
# ==================== PACKAGING TESTS ====================
|
||||
- name: Test packaging/daemon entry points
|
||||
run: |
|
||||
echo "Testing both entry point methods..."
|
||||
python -m praisonai --version
|
||||
praisonai --version
|
||||
|
||||
- name: Test doctor packaging command
|
||||
run: |
|
||||
echo "Testing doctor packaging diagnostics..."
|
||||
praisonai doctor packaging --json
|
||||
|
||||
# ==================== REAL API TESTS ====================
|
||||
- name: Real API test - Agent run
|
||||
if: env.OPENAI_API_KEY != ''
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
modules = ["python-3.12", "nodejs-20", "rust-stable", "bash"]
|
||||
[agent]
|
||||
expertMode = true
|
||||
integrations = ["github:1.0.0"]
|
||||
|
||||
[nix]
|
||||
channel = "stable-25_05"
|
||||
packages = ["libxcrypt"]
|
||||
|
||||
[[ports]]
|
||||
localPort = 5000
|
||||
externalPort = 80
|
||||
|
||||
[[ports]]
|
||||
localPort = 8000
|
||||
externalPort = 8000
|
||||
|
||||
[workflows]
|
||||
runButton = "Project"
|
||||
|
||||
[[workflows.workflow]]
|
||||
name = "Project"
|
||||
mode = "parallel"
|
||||
author = "agent"
|
||||
|
||||
[[workflows.workflow.tasks]]
|
||||
task = "workflow.run"
|
||||
args = "Start application"
|
||||
|
||||
[[workflows.workflow.tasks]]
|
||||
task = "workflow.run"
|
||||
args = "Backend API"
|
||||
|
||||
[[workflows.workflow]]
|
||||
name = "Start application"
|
||||
author = "agent"
|
||||
|
||||
[workflows.workflow.metadata]
|
||||
outputType = "webview"
|
||||
|
||||
[[workflows.workflow.tasks]]
|
||||
task = "shell.exec"
|
||||
args = "python run.py"
|
||||
waitForPort = 5000
|
||||
|
||||
[[workflows.workflow]]
|
||||
name = "Backend API"
|
||||
author = "agent"
|
||||
|
||||
[[workflows.workflow.tasks]]
|
||||
task = "shell.exec"
|
||||
args = "python backend/main.py"
|
||||
waitForPort = 8000
|
||||
|
||||
[workflows.workflow.metadata]
|
||||
outputType = "console"
|
||||
|
||||
[deployment]
|
||||
deploymentTarget = "autoscale"
|
||||
run = ["python", "run.py"]
|
||||
@@ -1,14 +0,0 @@
|
||||
# Contributing to PraisonAI
|
||||
|
||||
Thank you for your interest! Here's how to get started:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Submit a pull request
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Follow existing code style
|
||||
- Add tests for new features
|
||||
- Update documentation as needed
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
PraisonAI 🦞 — **Hire a 24/7 AI Workforce.** Stop writing boilerplate and start shipping autonomous, self-improving agents that research, plan, and execute tasks across your apps. From one agent to an entire organization, deployed in 5 lines of code.
|
||||
PraisonAI 🦞 — **Hire a 24/7 AI Workforce.** Stop writing boilerplate and start shipping autonomous agents that research, plan, and execute tasks across your apps. From one agent to an entire organization, deployed in 5 lines of code.
|
||||
|
||||
```bash
|
||||
curl -fsSL https://praison.ai/install.sh | bash
|
||||
@@ -294,35 +294,8 @@ def search(query: str) -> str:
|
||||
|
||||
@tool
|
||||
def calculate(expression: str) -> float:
|
||||
"""Safely evaluate a numeric arithmetic expression."""
|
||||
import ast
|
||||
import operator
|
||||
|
||||
# Define allowed operations
|
||||
_OPS = {
|
||||
ast.Add: operator.add,
|
||||
ast.Sub: operator.sub,
|
||||
ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv,
|
||||
ast.Pow: operator.pow,
|
||||
ast.USub: operator.neg,
|
||||
ast.UAdd: operator.pos,
|
||||
}
|
||||
|
||||
def _safe_eval(node):
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
|
||||
return node.value
|
||||
elif isinstance(node, ast.BinOp) and type(node.op) in _OPS:
|
||||
return _OPS[type(node.op)](_safe_eval(node.left), _safe_eval(node.right))
|
||||
elif isinstance(node, ast.UnaryOp) and type(node.op) in _OPS:
|
||||
return _OPS[type(node.op)](_safe_eval(node.operand))
|
||||
else:
|
||||
raise ValueError("Unsupported expression")
|
||||
|
||||
try:
|
||||
return _safe_eval(ast.parse(expression, mode="eval").body)
|
||||
except (ValueError, SyntaxError, TypeError, ZeroDivisionError, OverflowError):
|
||||
raise ValueError("Invalid arithmetic expression")
|
||||
"""Evaluate a math expression."""
|
||||
return eval(expression)
|
||||
|
||||
agent = Agent(
|
||||
instructions="You are a helpful assistant",
|
||||
@@ -331,7 +304,6 @@ agent = Agent(
|
||||
agent.start("Search for AI news and calculate 15*4")
|
||||
```
|
||||
|
||||
> ⚠️ **Security Note:** Never use `eval()`, `exec()`, or `subprocess` in tool functions that process LLM-generated or user-supplied input. Always validate and sanitize inputs to prevent code injection attacks.
|
||||
> 📖 [Full tools docs](https://docs.praison.ai/docs/tools/tools) — BaseTool, tool packages, 100+ built-in tools
|
||||
|
||||
### 5. Persistence (Databases)
|
||||
@@ -358,15 +330,6 @@ pip install "praisonai[claw]"
|
||||
praisonai claw
|
||||
```
|
||||
|
||||
#### Required Environment Variables
|
||||
|
||||
Copy `.env.example` to `.env` and configure the following variables:
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `OPENAI_API_KEY` | Yes | OpenAI API key for all LLM calls |
|
||||
| `TAVILY_API_KEY` | Yes (Claw) | Tavily key for the built-in web-search tool. Get one free at https://app.tavily.com |
|
||||
|
||||
Open **http://localhost:8082** — the dashboard comes with 13 built-in pages: Chat, Agents, Memory, Knowledge, Channels, Guardrails, Cron, and more. Add messaging channels directly from the UI.
|
||||
|
||||
> 📖 [Full Claw docs](https://docs.praison.ai/docs/concepts/claw) — platform tokens, CLI options, Docker, and YAML agent mode
|
||||
@@ -382,7 +345,7 @@ praisonai flow
|
||||
|
||||
Open **http://localhost:7861** — use the **Agent** and **Agent Team** components to create sequential or parallel workflows. Connect Chat Input → Agent Team → Chat Output for instant multi-agent pipelines.
|
||||
|
||||
> 📖 [Full Flow docs](https://docs.praison.ai/docs/concepts/agentflow) — visual agent building, component reference, and deployment
|
||||
> 📖 [Full Flow docs](https://docs.praison.ai/docs/concepts/flow) — visual agent building, component reference, and deployment
|
||||
|
||||
### 8. PraisonAI UI 🤖 (Clean Chat)
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ Methods:
|
||||
* <code title="class GuardrailResult">GuardrailResult.<a href="./src/praisonai-agents/praisonaiagents/guardrails/guardrail_result.py">from_tuple</a>(result: Tuple[bool, Any]) -> 'GuardrailResult'</code>
|
||||
* <code title="class HandoffConfig">HandoffConfig.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">from_dict</a>(data: Dict[str, Any]) -> 'HandoffConfig'</code>
|
||||
* <code title="class HandoffConfig">HandoffConfig.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class HandoffResult">HandoffResult.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">from_outcome</a>(outcome: AgentRunOutcome, target_agent: Optional[str] = None, source_agent: Optional[str] = None, handoff_depth: int = 0) -> 'HandoffResult'</code>
|
||||
* <code title="class TaskOutput">TaskOutput.<a href="./src/praisonai-agents/praisonaiagents/main.py">json</a>() -> Optional[str]</code>
|
||||
* <code title="class TaskOutput">TaskOutput.<a href="./src/praisonai-agents/praisonaiagents/main.py">to_dict</a>() -> dict</code>
|
||||
* <code title="class ToolResult">ToolResult.<a href="./src/praisonai-agents/praisonaiagents/tools/base.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
@@ -41,7 +40,6 @@ Methods:
|
||||
* <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>() -> Optional[bool]</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">checkpoints</a>(value: Optional[bool]) -> None</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">clone_for_channel</a>() -> 'Agent'</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">close</a>() -> None</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">console</a>() -> Optional[Any]</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">context_manager</a>() -> Optional[Any]</code>
|
||||
@@ -76,7 +74,7 @@ Methods:
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run_until</a>(prompt: str, criteria: str, threshold: float = 8.0, max_iterations: int = 5, mode: str = 'optimize', on_iteration: Optional[Callable[[Any], None]] = None, verbose: bool = False) -> 'EvaluationLoopResult'</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">run_until_async</a>(prompt: str, criteria: str, threshold: float = 8.0, max_iterations: int = 5, mode: str = 'optimize', on_iteration: Optional[Callable[[Any], None]] = None, verbose: bool = False) -> 'EvaluationLoopResult'</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">skill_manager</a>() -> Optional[Any]</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', action: str = 'add', **kwargs: Any) -> None</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: Any) -> None</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">stream_emitter</a>() -> Optional[Any]</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">stream_emitter</a>(value: Optional[Any]) -> None</code>
|
||||
* <code title="class Agent">Agent.<a href="./src/praisonai-agents/praisonaiagents/agent/agent.py">thinking_budget</a>() -> Optional[int]</code>
|
||||
@@ -173,10 +171,7 @@ Methods:
|
||||
* <code title="class BaseTool">BaseTool.<a href="./src/praisonai-agents/praisonaiagents/tools/base.py">safe_run</a>(**kwargs) -> ToolResult</code>
|
||||
* <code title="class BaseTool">BaseTool.<a href="./src/praisonai-agents/praisonaiagents/tools/base.py">validate</a>() -> bool</code>
|
||||
* <code title="class BaseTool">BaseTool.<a href="./src/praisonai-agents/praisonaiagents/tools/base.py">validate_class</a>() -> bool</code>
|
||||
* <code title="class BaseTool">BaseTool.<a href="./src/praisonai-agents/praisonaiagents/tools/base.py">validate_schema_roundtrip</a>() -> bool</code>
|
||||
* <code title="class FunctionTool">FunctionTool.<a href="./src/praisonai-agents/praisonaiagents/tools/decorator.py">__call__</a>(*args, **kwargs) -> Any</code>
|
||||
* <code title="class FunctionTool">FunctionTool.<a href="./src/praisonai-agents/praisonaiagents/tools/decorator.py">check_availability</a>() -> tuple[bool, str]</code>
|
||||
* <code title="class FunctionTool">FunctionTool.<a href="./src/praisonai-agents/praisonaiagents/tools/decorator.py">get_schema</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class FunctionTool">FunctionTool.<a href="./src/praisonai-agents/praisonaiagents/tools/decorator.py">injected_params</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class FunctionTool">FunctionTool.<a href="./src/praisonai-agents/praisonaiagents/tools/decorator.py">run</a>(**kwargs) -> Any</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">clear</a>() -> None</code>
|
||||
@@ -184,18 +179,14 @@ Methods:
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">discover_single_file_plugins</a>() -> int</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">get</a>(name: str) -> Optional[Union[BaseTool, Callable]]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">get_all</a>() -> Dict[str, Union[BaseTool, Callable]]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">get_tool_definitions</a>() -> List[Dict[str, Any]]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">get_trust_level</a>(name: str) -> Optional[str]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">list_available_tools</a>(context: Optional[Dict[str, Any]] = None, ttl_seconds: Optional[float] = None) -> List[Union[BaseTool, Callable]]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">list_base_tools</a>() -> List[BaseTool]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">list_tools</a>() -> List[str]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">list_tools_with_allowed_filter</a>(context: Optional[Dict[str, Any]] = None) -> List[str]</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">register</a>(tool: Union[BaseTool, Callable], name: Optional[str] = None, overwrite: bool = False, trust_level: Optional[str] = None, dynamic_schema_overrides: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None) -> None</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">register</a>(tool: Union[BaseTool, Callable], name: Optional[str] = None, overwrite: bool = False) -> None</code>
|
||||
* <code title="class ToolRegistry">ToolRegistry.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">unregister</a>(name: str) -> bool</code>
|
||||
* <code title="class Tools">Tools.<a href="./src/praisonai-agents/praisonaiagents/tools/tools.py">internet_search</a>(*args, **kwargs)</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">get_registry</a>() -> ToolRegistry</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">get_tool</a>(name: str) -> Optional[Union[BaseTool, Callable]]</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">register_tool</a>(tool: Union[BaseTool, Callable], name: Optional[str] = None, trust_level: Optional[str] = None, dynamic_schema_overrides: Optional[Callable[[Dict[str, Any]], Dict[str, Any]]] = None) -> None</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/tools/registry.py">register_tool</a>(tool: Union[BaseTool, Callable], name: Optional[str] = None) -> None</code>
|
||||
* <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>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/tools/base.py">validate_tool</a>(tool: Any) -> bool</code>
|
||||
|
||||
@@ -215,12 +206,11 @@ Methods:
|
||||
* <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">get_next_task</a>(context: Dict[str, Any]) -> Optional[str]</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">initialize_memory_async</a>()</code>
|
||||
* <code title="class Task">Task.<a href="./src/praisonai-agents/praisonaiagents/task/task.py">set_status</a>(new_status: str) -> None</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>
|
||||
* <code title="class Task">Task.<a href="./src/praisonai-agents/praisonaiagents/task/task.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">loop</a>(step: Any = None, steps: Optional[List[Any]] = None, over: Optional[str] = None, from_csv: Optional[str] = None, from_file: Optional[str] = None, var_name: str = 'item', parallel: bool = False, max_workers: Optional[int] = None, output_variable: Optional[str] = None) -> Loop</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">parallel</a>(steps: List, max_workers: Optional[int] = None, on_failure: str = 'partial_ok') -> Parallel</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">parallel</a>(steps: List) -> Parallel</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">repeat</a>(step: Any, until: Optional[Callable[[WorkflowContext], bool]] = None, max_iterations: int = 10) -> Repeat</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">route</a>(routes: Dict[str, List], default: Optional[List] = None) -> Route</code>
|
||||
|
||||
@@ -357,7 +347,7 @@ Methods:
|
||||
* <code title="class Handoff">Handoff.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">to_tool_function</a>(source_agent: 'Agent') -> Callable</code>
|
||||
* <code title="class Handoff">Handoff.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">tool_description</a>() -> str</code>
|
||||
* <code title="class Handoff">Handoff.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">tool_name</a>() -> str</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">handoff</a>(agent: 'Agent', tool_name_override: Optional[str] = None, tool_description_override: Optional[str] = None, on_handoff: Optional[Callable] = None, input_type: Optional[type] = None, input_filter: Optional[Callable[[HandoffInputData], HandoffInputData]] = None, config: Optional[HandoffConfig] = None, context_policy: Optional[str] = None, timeout_seconds: Optional[float] = None, max_concurrent: Optional[int] = None, detect_cycles: Optional[bool] = None, max_depth: Optional[int] = None, tool_policy_mode: Optional[Literal['intersect', 'passthrough']] = None, blocked_tools: Optional[List[str]] = None) -> Handoff</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">handoff</a>(agent: 'Agent', tool_name_override: Optional[str] = None, tool_description_override: Optional[str] = None, on_handoff: Optional[Callable] = None, input_type: Optional[type] = None, input_filter: Optional[Callable[[HandoffInputData], HandoffInputData]] = None, config: Optional[HandoffConfig] = None, context_policy: Optional[str] = None, timeout_seconds: Optional[float] = None, max_concurrent: Optional[int] = None, detect_cycles: Optional[bool] = None, max_depth: Optional[int] = None) -> Handoff</code>
|
||||
* <code title="class handoff_filters">handoff_filters.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">compress_history</a>(data: HandoffInputData) -> HandoffInputData</code>
|
||||
* <code title="class handoff_filters">handoff_filters.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">keep_last_n_messages</a>(n: int) -> Callable[[HandoffInputData], HandoffInputData]</code>
|
||||
* <code title="class handoff_filters">handoff_filters.<a href="./src/praisonai-agents/praisonaiagents/agent/handoff.py">remove_all_tools</a>(data: HandoffInputData) -> HandoffInputData</code>
|
||||
@@ -477,26 +467,17 @@ Methods:
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">activate_by_name</a>(name: str) -> bool</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">add_skill</a>(skill_path: str) -> Optional[LoadedSkill]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">clear</a>() -> None</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">create_skill</a>(name: str, content: str, category: str = None) -> dict</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">delete_skill</a>(name: str) -> dict</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">discover</a>(skill_dirs: Optional[List[str]] = None, include_defaults: bool = True) -> int</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">edit_skill</a>(name: str, content: str) -> dict</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_allowed_tools</a>(name: str) -> List[str]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_available_skills</a>() -> List[SkillMetadata]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_available_skills_by_state</a>(state: SkillState) -> List[LoadedSkill]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_instructions</a>(name: str) -> Optional[str]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_skill</a>(name: str) -> Optional[LoadedSkill]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_skills_diagnostics</a>() -> Dict[str, ValidationResult]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">get_user_invocable_skills</a>() -> List[LoadedSkill]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">invoke</a>(name: str, raw_args: str = '', session_id: Optional[str] = None, shell_exec: bool = False) -> Optional[str]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">load_resources</a>(name: str) -> bool</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">patch_skill</a>(name: str, old_string: str, new_string: str, file_path: str = None, replace_all: bool = False) -> dict</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">remove_skill_file</a>(name: str, file_path: str) -> dict</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">skill_names</a>() -> List[str]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">skills</a>() -> List[LoadedSkill]</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">to_prompt</a>() -> str</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">validate_skill_capabilities</a>(skill_name: str, force_refresh: bool = False) -> ValidationResult</code>
|
||||
* <code title="class SkillManager">SkillManager.<a href="./src/praisonai-agents/praisonaiagents/skills/manager.py">write_skill_file</a>(name: str, file_path: str, file_content: str) -> dict</code>
|
||||
* <code title="class SkillMetadata">SkillMetadata.<a href="./src/praisonai-agents/praisonaiagents/skills/models.py">from_properties</a>(props: SkillProperties) -> 'SkillMetadata'</code>
|
||||
* <code title="class SkillProperties">SkillProperties.<a href="./src/praisonai-agents/praisonaiagents/skills/models.py">to_dict</a>() -> dict</code>
|
||||
* <code title="class SkillsConfig">SkillsConfig.<a href="./src/praisonai-agents/praisonaiagents/config/feature_configs.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
@@ -611,13 +592,6 @@ Methods:
|
||||
* <code title="class ContextManager">ContextManager.<a href="./src/praisonai-agents/praisonaiagents/context/manager.py">set_tool_budget</a>(tool_name: str, max_tokens: int, protected: bool = False) -> None</code>
|
||||
* <code title="class ContextManager">ContextManager.<a href="./src/praisonai-agents/praisonaiagents/context/manager.py">truncate_tool_output</a>(tool_name: str, output: str) -> str</code>
|
||||
|
||||
# UI
|
||||
|
||||
Types:
|
||||
```python
|
||||
from praisonaiagents import A2UI
|
||||
```
|
||||
|
||||
# Config
|
||||
|
||||
Types:
|
||||
@@ -630,7 +604,6 @@ Methods:
|
||||
* <code title="class AutonomyConfig">AutonomyConfig.<a href="./src/praisonai-agents/praisonaiagents/agent/autonomy.py">effective_track_changes</a>() -> bool</code>
|
||||
* <code title="class AutonomyConfig">AutonomyConfig.<a href="./src/praisonai-agents/praisonaiagents/agent/autonomy.py">from_dict</a>(data: Dict[str, Any]) -> 'AutonomyConfig'</code>
|
||||
* <code title="class CachingConfig">CachingConfig.<a href="./src/praisonai-agents/praisonaiagents/config/feature_configs.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class ExecutionConfig">ExecutionConfig.<a href="./src/praisonai-agents/praisonaiagents/config/feature_configs.py">from_dict</a>(data: Dict[str, Any]) -> 'ExecutionConfig'</code>
|
||||
* <code title="class ExecutionConfig">ExecutionConfig.<a href="./src/praisonai-agents/praisonaiagents/config/feature_configs.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class GuardrailConfig">GuardrailConfig.<a href="./src/praisonai-agents/praisonaiagents/config/feature_configs.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class HooksConfig">HooksConfig.<a href="./src/praisonai-agents/praisonaiagents/config/feature_configs.py">to_dict</a>() -> Dict[str, Any]</code>
|
||||
@@ -723,19 +696,14 @@ Methods:
|
||||
* <code title="class AgentFlow">AgentFlow.<a href="./src/praisonai-agents/praisonaiagents/workflows/workflows.py">verbose</a>(value: bool)</code>
|
||||
* <code title="class AgentOSProtocol">AgentOSProtocol.<a href="./src/praisonai-agents/praisonaiagents/app/protocols.py">get_app</a>() -> Any</code>
|
||||
* <code title="class AgentOSProtocol">AgentOSProtocol.<a href="./src/praisonai-agents/praisonaiagents/app/protocols.py">serve</a>(host: Optional[str] = None, port: Optional[int] = None, reload: bool = False, **kwargs: Any) -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">aannounce_completion</a>(agent_id: str, task_id: str, result: Any, success: bool = True, error: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">add_task</a>(task)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">aexecute_task</a>(task_id)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">announce_completion</a>(agent_id: str, task_id: str, result: Any, success: bool = True, error: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None) -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<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 AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">arun_all_tasks</a>()</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">arun_task</a>(task_id)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">aspawn_sub_agent</a>(agent: Agent, task: Any, completion_callback: Optional[Callable[[SubAgentCompletionEvent], Any]] = None, metadata: Optional[Dict[str, Any]] = None) -> SpawnedSubAgent</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">astart</a>(content = None, return_dict = False, **kwargs)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">await_for_completions</a>(timeout: Optional[float] = None, agent_ids: Optional[List[str]] = None) -> List[SubAgentCompletionEvent]</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">clean_json_output</a>(output: str) -> str</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">clear_state</a>() -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">close</a>() -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">context_manager</a>()</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">current_plan</a>()</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">default_completion_checker</a>(task, agent_output)</code>
|
||||
@@ -747,7 +715,6 @@ Methods:
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_all_tasks_status</a>()</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_detailed_token_report</a>() -> Dict[str, Any]</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_plan_markdown</a>() -> str</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_spawned_agents</a>() -> List[SpawnedSubAgent]</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_state</a>(key: str, default: Any = None) -> Any</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_task_details</a>(task_id)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">get_task_result</a>(task_id)</code>
|
||||
@@ -764,12 +731,10 @@ Methods:
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">save_output_to_file</a>(task, task_output)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<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 AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">set_state</a>(key: str, value: Any) -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">spawn_sub_agent</a>(agent: Agent, task: Any, completion_callback: Optional[Callable[[SubAgentCompletionEvent], Any]] = None, metadata: Optional[Dict[str, Any]] = None) -> SpawnedSubAgent</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">start</a>(content = None, return_dict = False, output = None, **kwargs)</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">todo_list</a>()</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">update_plan_step_status</a>(step_id: str, status: str) -> bool</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">update_state</a>(updates: Dict) -> None</code>
|
||||
* <code title="class AgentTeam">AgentTeam.<a href="./src/praisonai-agents/praisonaiagents/agents/agents.py">wait_for_completions</a>(timeout: Optional[float] = None, agent_ids: Optional[List[str]] = None) -> List[SubAgentCompletionEvent]</code>
|
||||
* <code title="class AutoApproveBackend">AutoApproveBackend.<a href="./src/praisonai-agents/praisonaiagents/approval/backends.py">request_approval</a>(request: ApprovalRequest) -> ApprovalDecision</code>
|
||||
* <code title="class AutoApproveBackend">AutoApproveBackend.<a href="./src/praisonai-agents/praisonaiagents/approval/backends.py">request_approval_sync</a>(request: ApprovalRequest) -> ApprovalDecision</code>
|
||||
* <code title="function">praisonaiagents.<a href="./src/praisonai-agents/praisonaiagents/embedding/embed.py">aembedding</a>(input: Union[str, List[str]], model: str = 'text-embedding-3-small', dimensions: Optional[int] = None, encoding_format: str = 'float', timeout: float = 600.0, api_key: Optional[str] = None, api_base: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None, **kwargs) -> EmbeddingResult</code>
|
||||
@@ -780,7 +745,7 @@ Methods:
|
||||
|
||||
Types:
|
||||
```python
|
||||
from praisonai import Agent, AgentApp, AgentOS, AnthropicManagedAgent, CloudProvider, DB, Deploy, DeployConfig, DeployType, HostedAgent, HostedAgentConfig, LocalAgent, LocalAgentConfig, LocalManagedAgent, LocalManagedConfig, ManagedAgent, ManagedConfig, PraisonAI, __version__, arun, run, run_integrated_gateway
|
||||
from praisonai import AgentApp, AgentOS, AnthropicManagedAgent, CloudProvider, DB, Deploy, DeployConfig, DeployType, LocalManagedAgent, LocalManagedConfig, ManagedAgent, ManagedConfig, PraisonAI, __version__
|
||||
```
|
||||
|
||||
# CLI
|
||||
@@ -811,10 +776,6 @@ Methods:
|
||||
* <code title="cli">praisonai bot discord <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot email <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot install-daemon <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot linear <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot list <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot purge <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot replay <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot slack <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot start <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
* <code title="cli">praisonai bot telegram <a href="./src/praisonai/praisonai/cli/commands/bot.py">--help</a></code>
|
||||
@@ -882,10 +843,8 @@ Methods:
|
||||
* <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 packaging <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 skills <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>
|
||||
@@ -913,28 +872,14 @@ Methods:
|
||||
* <code title="cli">praisonai gateway gateway-callback <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway install <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway logs <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway mint-link <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway send <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway start <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway status <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway stop <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai gateway uninstall <a href="./src/praisonai/praisonai/cli/commands/gateway.py">--help</a></code>
|
||||
* <code title="cli">praisonai github triage <a href="./src/praisonai/praisonai/cli/commands/github.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 kanban block <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban boards <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban comment <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban complete <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban create <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban dispatch <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban link <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban list <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban move <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban reclaim <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban show <a href="./src/praisonai/praisonai/cli/commands/kanban.py">--help</a></code>
|
||||
* <code title="cli">praisonai kanban unblock <a href="./src/praisonai/praisonai/cli/commands/kanban.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>
|
||||
@@ -999,10 +944,6 @@ Methods:
|
||||
* <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 pairing approve <a href="./src/praisonai/praisonai/cli/commands/pairing.py">--help</a></code>
|
||||
* <code title="cli">praisonai pairing clear <a href="./src/praisonai/praisonai/cli/commands/pairing.py">--help</a></code>
|
||||
* <code title="cli">praisonai pairing list <a href="./src/praisonai/praisonai/cli/commands/pairing.py">--help</a></code>
|
||||
* <code title="cli">praisonai pairing revoke <a href="./src/praisonai/praisonai/cli/commands/pairing.py">--help</a></code>
|
||||
* <code title="cli">praisonai paths show <a href="./src/praisonai/praisonai/cli/commands/paths.py">--help</a></code>
|
||||
* <code title="cli">praisonai plugins create <a href="./src/praisonai/praisonai/cli/commands/plugins.py">--help</a></code>
|
||||
* <code title="cli">praisonai plugins disable <a href="./src/praisonai/praisonai/cli/commands/plugins.py">--help</a></code>
|
||||
@@ -1092,7 +1033,6 @@ Methods:
|
||||
* <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 serve ui <a href="./src/praisonai/praisonai/cli/commands/serve.py">--help</a></code>
|
||||
* <code title="cli">praisonai serve ui-gateway <a href="./src/praisonai/praisonai/cli/commands/serve.py">--help</a></code>
|
||||
* <code title="cli">praisonai serve unified <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>
|
||||
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
Build a clean, modern web dashboard for managing and interacting with AI agents powered by PraisonAI. Use React + Vite for the frontend, and a simple Python FastAPI backend. Keep it simple but functional — no overengineering.
|
||||
|
||||
---
|
||||
|
||||
## TECH STACK
|
||||
- Frontend: React + Vite + TailwindCSS (CDN, no build step for Tailwind)
|
||||
- Backend: FastAPI (Python)
|
||||
- Storage: JSON files (no database needed yet, keep it simple)
|
||||
- API calls: fetch() to the FastAPI backend
|
||||
|
||||
---
|
||||
|
||||
## PROJECT STRUCTURE
|
||||
/backend
|
||||
main.py # FastAPI app
|
||||
agents_store.json # persists agent definitions
|
||||
history_store.json # persists conversation history
|
||||
|
||||
/frontend
|
||||
index.html
|
||||
src/
|
||||
App.jsx
|
||||
components/
|
||||
Sidebar.jsx
|
||||
AgentList.jsx
|
||||
AgentDetail.jsx
|
||||
ChatPanel.jsx
|
||||
ActivityLog.jsx
|
||||
AgentForm.jsx
|
||||
|
||||
---
|
||||
|
||||
## BACKEND (FastAPI - main.py)
|
||||
|
||||
Create these REST endpoints:
|
||||
|
||||
### Agents CRUD
|
||||
GET /agents → list all agents
|
||||
POST /agents → create agent
|
||||
PUT /agents/{id} → update agent
|
||||
DELETE /agents/{id} → delete agent
|
||||
GET /agents/{id} → get single agent details
|
||||
|
||||
### Chat
|
||||
POST /agents/{id}/chat → send message to agent, returns response + activity log
|
||||
GET /agents/{id}/history → get full conversation history
|
||||
DELETE /agents/{id}/history → clear history
|
||||
|
||||
### Activity
|
||||
GET /agents/{id}/activity → get activity log (tools used, connections, actions)
|
||||
|
||||
Each agent object should look like:
|
||||
{
|
||||
"id": "uuid",
|
||||
"name": "string",
|
||||
"role": "string",
|
||||
"instructions": "string",
|
||||
"tools": ["list of tool names"],
|
||||
"connections": ["other agent ids or external APIs"],
|
||||
"llm": "string (e.g. gpt-4o-mini)",
|
||||
"created_at": "timestamp",
|
||||
"status": "active | inactive"
|
||||
}
|
||||
|
||||
Each chat call should:
|
||||
1. Load agent config
|
||||
2. Run a PraisonAI agent with that config
|
||||
3. Capture stdout/tool calls/actions into an activity log entry
|
||||
4. Save message + response + activity to history
|
||||
5. Return all of it in one response
|
||||
|
||||
---
|
||||
|
||||
## FRONTEND LAYOUT
|
||||
|
||||
Split into 3 columns:
|
||||
|
||||
### LEFT SIDEBAR (narrow)
|
||||
- App logo/name "AgentOS"
|
||||
- List of all agents (name + status dot green/grey)
|
||||
- "+ New Agent" button at bottom
|
||||
- Click agent → loads it in center panel
|
||||
|
||||
### CENTER PANEL (main)
|
||||
Two tabs at top: "Chat" | "Details"
|
||||
|
||||
#### Chat tab:
|
||||
- Conversation history (bubbles: user right, agent left)
|
||||
- Each agent message has a collapsible "Activity" section below it showing:
|
||||
- What tools were called
|
||||
- What external connections were used
|
||||
- Raw output / reasoning steps
|
||||
- Input box at bottom + Send button
|
||||
- "Clear History" button top right
|
||||
|
||||
#### Details tab:
|
||||
- Shows agent config (name, role, instructions, LLM, tools, connections)
|
||||
- Edit button → opens inline form to modify
|
||||
- Shows stats: total messages, last active, tools used count
|
||||
|
||||
### RIGHT PANEL (narrower)
|
||||
- "Activity Feed" — real-time log of what the selected agent has done
|
||||
- Each entry: timestamp, action type (tool_call, api_call, message, error), short description
|
||||
- Color coded: blue=tool, green=success, red=error, grey=message
|
||||
- Scrollable, newest at top
|
||||
|
||||
---
|
||||
|
||||
## AGENT FORM (Add/Edit modal or inline)
|
||||
Fields:
|
||||
- Name (text input)
|
||||
- Role (text input, short description)
|
||||
- Instructions / System Prompt (large textarea)
|
||||
- LLM Model (dropdown: gpt-4o-mini, gpt-4o, claude-3-haiku, claude-sonnet, gemini-flash)
|
||||
- Tools (multi-select checkboxes): web_search, code_interpreter, file_reader, calculator, wikipedia
|
||||
- Connections (text inputs, add/remove rows): label + URL or agent name
|
||||
- Status toggle (active/inactive)
|
||||
Save / Cancel buttons
|
||||
|
||||
---
|
||||
|
||||
## STYLE GUIDE
|
||||
- Dark theme (background #0f1117, panels #1a1d27, accent #6c63ff purple)
|
||||
- Clean sans-serif font (Inter from Google Fonts)
|
||||
- Subtle borders (#2a2d3e)
|
||||
- Agent status dot: green (#22c55e) active, grey (#6b7280) inactive
|
||||
- Activity log colors: blue (#3b82f6) tool, green (#22c55e) success, red (#ef4444) error
|
||||
- Rounded corners (8px), subtle shadows
|
||||
- Mobile responsive (sidebar collapses to hamburger on small screens)
|
||||
|
||||
---
|
||||
|
||||
## SAMPLE DATA
|
||||
Pre-populate agents_store.json with 2 example agents so the UI is not empty:
|
||||
|
||||
Agent 1:
|
||||
- Name: "Research Agent"
|
||||
- Role: "Searches the web and summarizes information"
|
||||
- Tools: web_search, wikipedia
|
||||
- LLM: gpt-4o-mini
|
||||
|
||||
Agent 2:
|
||||
- Name: "Code Agent"
|
||||
- Role: "Writes and explains code"
|
||||
- Tools: code_interpreter, calculator
|
||||
- LLM: gpt-4o-mini
|
||||
|
||||
---
|
||||
|
||||
## IMPORTANT CONSTRAINTS
|
||||
- No TypeScript (plain JSX only)
|
||||
- No Redux (useState/useEffect only)
|
||||
- No external UI libraries (just Tailwind utility classes)
|
||||
- JSON file storage only (no SQLite, no Postgres)
|
||||
- Keep each file under 200 lines if possible, split into components
|
||||
- PraisonAI backend calls should use praisonaiagents library
|
||||
- Add CORS middleware to FastAPI so frontend can call backend freely
|
||||
- Read OPENAI_API_KEY from environment variable (os.environ)
|
||||
|
||||
---
|
||||
|
||||
## DELIVERABLE
|
||||
- Working React frontend that talks to FastAPI backend
|
||||
- I can add/edit/delete agents via the UI
|
||||
- I can chat with any agent and see what it does
|
||||
- History is saved and persists across page refreshes
|
||||
- Activity log updates after each interaction
|
||||
- README with how to run both frontend and backend
|
||||
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": "agent-001",
|
||||
"name": "Research Agent",
|
||||
"role": "Searches the web and summarizes information",
|
||||
"instructions": "You are a research assistant. Search the web and Wikipedia to find accurate, up-to-date information. Summarize findings clearly and concisely. Always cite your sources.",
|
||||
"tools": ["web_search", "wikipedia"],
|
||||
"connections": [],
|
||||
"llm": "gpt-4o-mini",
|
||||
"created_at": "2025-01-01T00:00:00Z",
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "agent-002",
|
||||
"name": "Code Agent",
|
||||
"role": "Writes and explains code",
|
||||
"instructions": "You are a coding assistant. Write clean, well-commented code. Explain how code works step by step. Help debug issues and suggest improvements.",
|
||||
"tools": ["code_interpreter", "calculator"],
|
||||
"connections": [],
|
||||
"llm": "gpt-4o-mini",
|
||||
"created_at": "2025-01-01T00:00:00Z",
|
||||
"status": "active"
|
||||
}
|
||||
]
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
"""SQLite persistence for AgentOS agents and chat history."""
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timezone
|
||||
from typing import Dict, Iterator, List, Optional
|
||||
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
DB_FILE = os.environ.get("AGENTOS_DB", os.path.join(BASE_DIR, "agentos.db"))
|
||||
LEGACY_AGENTS_FILE = os.path.join(BASE_DIR, "agents_store.json")
|
||||
LEGACY_HISTORY_FILE = os.path.join(BASE_DIR, "history_store.json")
|
||||
|
||||
ALLOWED_STATUS = {"active", "auditing", "decommissioned"}
|
||||
|
||||
SCHEMA = """
|
||||
CREATE TABLE IF NOT EXISTS agents (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
instructions TEXT NOT NULL DEFAULT '',
|
||||
model TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'active'
|
||||
CHECK (status IN ('active', 'auditing', 'decommissioned')),
|
||||
generation INTEGER NOT NULL DEFAULT 1,
|
||||
parent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
|
||||
performance_score REAL,
|
||||
token_spend INTEGER NOT NULL DEFAULT 0,
|
||||
exit_summary TEXT,
|
||||
role TEXT,
|
||||
tools TEXT DEFAULT '[]',
|
||||
connections TEXT DEFAULT '[]',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS chat_history (
|
||||
id TEXT PRIMARY KEY,
|
||||
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
||||
user_message TEXT NOT NULL,
|
||||
agent_response TEXT NOT NULL,
|
||||
activity TEXT NOT NULL DEFAULT '[]',
|
||||
timestamp TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_history_agent_ts
|
||||
ON chat_history(agent_id, timestamp);
|
||||
"""
|
||||
|
||||
|
||||
@contextmanager
|
||||
def get_conn() -> Iterator[sqlite3.Connection]:
|
||||
conn = sqlite3.connect(DB_FILE)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute("PRAGMA foreign_keys = ON")
|
||||
try:
|
||||
yield conn
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def _now() -> str:
|
||||
# Timezone-aware UTC timestamp, ISO-8601 with trailing Z to match prior shape.
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f") + "Z"
|
||||
|
||||
|
||||
def _row_to_dict(row: sqlite3.Row) -> Dict:
|
||||
d = dict(row)
|
||||
# Legacy alias so existing frontend/clients that read `llm` still work.
|
||||
d["llm"] = d["model"]
|
||||
# Parse JSON fields
|
||||
try:
|
||||
d["tools"] = json.loads(d.get("tools") or "[]")
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
d["tools"] = []
|
||||
try:
|
||||
d["connections"] = json.loads(d.get("connections") or "[]")
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
d["connections"] = []
|
||||
return d
|
||||
|
||||
|
||||
def init_db() -> None:
|
||||
with get_conn() as conn:
|
||||
conn.executescript(SCHEMA)
|
||||
cur = conn.execute("SELECT COUNT(*) FROM agents")
|
||||
if cur.fetchone()[0] == 0:
|
||||
_migrate_from_json(conn)
|
||||
cur = conn.execute("SELECT COUNT(*) FROM chat_history")
|
||||
if cur.fetchone()[0] == 0:
|
||||
_migrate_history_from_json(conn)
|
||||
|
||||
|
||||
def _migrate_from_json(conn: sqlite3.Connection) -> None:
|
||||
if not os.path.exists(LEGACY_AGENTS_FILE):
|
||||
return
|
||||
try:
|
||||
with open(LEGACY_AGENTS_FILE) as f:
|
||||
legacy = json.load(f)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return
|
||||
for a in legacy:
|
||||
status = a.get("status", "active")
|
||||
if status not in ALLOWED_STATUS:
|
||||
status = "active"
|
||||
created = a.get("created_at") or _now()
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT OR IGNORE INTO agents
|
||||
(id, name, instructions, model, status, generation, parent_id,
|
||||
performance_score, token_spend, exit_summary, role, tools, connections, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 1, NULL, NULL, 0, NULL, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
a["id"],
|
||||
a.get("name", "Unnamed"),
|
||||
a.get("instructions", ""),
|
||||
a.get("llm") or a.get("model") or "gpt-4o-mini",
|
||||
status,
|
||||
a.get("role"),
|
||||
json.dumps(a.get("tools", [])),
|
||||
json.dumps(a.get("connections", [])),
|
||||
created,
|
||||
created,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _migrate_history_from_json(conn: sqlite3.Connection) -> None:
|
||||
if not os.path.exists(LEGACY_HISTORY_FILE):
|
||||
return
|
||||
try:
|
||||
with open(LEGACY_HISTORY_FILE) as f:
|
||||
legacy = json.load(f)
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return
|
||||
if not isinstance(legacy, dict):
|
||||
return
|
||||
for agent_id, entries in legacy.items():
|
||||
if not isinstance(entries, list):
|
||||
continue
|
||||
for entry in entries:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT OR IGNORE INTO chat_history
|
||||
(id, agent_id, user_message, agent_response, activity, timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
entry.get("id") or os.urandom(4).hex(),
|
||||
agent_id,
|
||||
entry.get("user_message", ""),
|
||||
entry.get("agent_response", ""),
|
||||
json.dumps(entry.get("activity", [])),
|
||||
entry.get("timestamp") or _now(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def list_agents() -> List[Dict]:
|
||||
with get_conn() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM agents ORDER BY created_at ASC"
|
||||
).fetchall()
|
||||
return [_row_to_dict(r) for r in rows]
|
||||
|
||||
|
||||
def get_agent(agent_id: str) -> Optional[Dict]:
|
||||
with get_conn() as conn:
|
||||
row = conn.execute(
|
||||
"SELECT * FROM agents WHERE id = ?", (agent_id,)
|
||||
).fetchone()
|
||||
return _row_to_dict(row) if row else None
|
||||
|
||||
|
||||
def create_agent(agent: Dict) -> Dict:
|
||||
now = _now()
|
||||
with get_conn() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO agents
|
||||
(id, name, instructions, model, status, generation, parent_id,
|
||||
performance_score, token_spend, exit_summary, role, tools, connections, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
agent["id"],
|
||||
agent["name"],
|
||||
agent.get("instructions", ""),
|
||||
agent["model"],
|
||||
agent.get("status", "active"),
|
||||
agent.get("generation", 1),
|
||||
agent.get("parent_id"),
|
||||
agent.get("performance_score"),
|
||||
agent.get("token_spend", 0),
|
||||
agent.get("exit_summary"),
|
||||
agent.get("role"),
|
||||
json.dumps(agent.get("tools", [])),
|
||||
json.dumps(agent.get("connections", [])),
|
||||
now,
|
||||
now,
|
||||
),
|
||||
)
|
||||
return get_agent(agent["id"]) # type: ignore[return-value]
|
||||
|
||||
|
||||
UPDATABLE_FIELDS = {
|
||||
"name",
|
||||
"instructions",
|
||||
"model",
|
||||
"status",
|
||||
"generation",
|
||||
"parent_id",
|
||||
"performance_score",
|
||||
"token_spend",
|
||||
"exit_summary",
|
||||
"role",
|
||||
"tools",
|
||||
"connections",
|
||||
}
|
||||
|
||||
|
||||
def update_agent(agent_id: str, fields: Dict) -> Optional[Dict]:
|
||||
sets = {k: v for k, v in fields.items() if k in UPDATABLE_FIELDS}
|
||||
if not sets:
|
||||
return get_agent(agent_id)
|
||||
# Serialize JSON fields
|
||||
for k in ["tools", "connections"]:
|
||||
if k in sets and isinstance(sets[k], list):
|
||||
sets[k] = json.dumps(sets[k])
|
||||
columns = ", ".join(f"{k} = ?" for k in sets) + ", updated_at = ?"
|
||||
values = list(sets.values()) + [_now(), agent_id]
|
||||
with get_conn() as conn:
|
||||
cur = conn.execute(
|
||||
f"UPDATE agents SET {columns} WHERE id = ?", values
|
||||
)
|
||||
if cur.rowcount == 0:
|
||||
return None
|
||||
return get_agent(agent_id)
|
||||
|
||||
|
||||
def delete_agent(agent_id: str) -> bool:
|
||||
with get_conn() as conn:
|
||||
cur = conn.execute("DELETE FROM agents WHERE id = ?", (agent_id,))
|
||||
return cur.rowcount > 0
|
||||
|
||||
|
||||
# ----- chat history --------------------------------------------------------
|
||||
|
||||
|
||||
def _row_to_history(row: sqlite3.Row) -> Dict:
|
||||
d = dict(row)
|
||||
try:
|
||||
d["activity"] = json.loads(d.get("activity") or "[]")
|
||||
except json.JSONDecodeError:
|
||||
d["activity"] = []
|
||||
d.pop("agent_id", None)
|
||||
return d
|
||||
|
||||
|
||||
def add_history_entry(agent_id: str, entry: Dict) -> Dict:
|
||||
with get_conn() as conn:
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO chat_history
|
||||
(id, agent_id, user_message, agent_response, activity, timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
entry["id"],
|
||||
agent_id,
|
||||
entry["user_message"],
|
||||
entry["agent_response"],
|
||||
json.dumps(entry.get("activity", [])),
|
||||
entry["timestamp"],
|
||||
),
|
||||
)
|
||||
return entry
|
||||
|
||||
|
||||
def list_history(agent_id: str) -> List[Dict]:
|
||||
with get_conn() as conn:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM chat_history WHERE agent_id = ? ORDER BY timestamp ASC",
|
||||
(agent_id,),
|
||||
).fetchall()
|
||||
return [_row_to_history(r) for r in rows]
|
||||
|
||||
|
||||
def clear_history(agent_id: str) -> None:
|
||||
with get_conn() as conn:
|
||||
conn.execute("DELETE FROM chat_history WHERE agent_id = ?", (agent_id,))
|
||||
|
||||
|
||||
def list_activity(agent_id: str, limit: int = 100) -> List[Dict]:
|
||||
"""Flattened activity across all of an agent's chat entries, newest first, capped."""
|
||||
entries = list_history(agent_id)
|
||||
activity: List[Dict] = []
|
||||
for entry in reversed(entries):
|
||||
activity.extend(entry.get("activity", []))
|
||||
return activity[:limit]
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
"""AgentOS FastAPI backend."""
|
||||
import os
|
||||
import uuid
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime, timezone
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
try:
|
||||
from . import db as agentdb # package import (uvicorn backend.main:app)
|
||||
except ImportError: # pragma: no cover - script execution fallback
|
||||
import sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import db as agentdb # type: ignore
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
agentdb.init_db()
|
||||
yield
|
||||
|
||||
|
||||
app = FastAPI(title="AgentOS API", lifespan=lifespan)
|
||||
|
||||
allowed_origins = os.environ.get("AGENTOS_CORS_ORIGINS", "http://localhost:5173").split(",")
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=allowed_origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
def _now_iso() -> str:
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f") + "Z"
|
||||
|
||||
|
||||
class AgentCreate(BaseModel):
|
||||
# Accept fields for frontend compatibility.
|
||||
# `protected_namespaces=()` silences Pydantic v2 warnings about the
|
||||
# `model` field name colliding with its protected namespace.
|
||||
model_config = ConfigDict(extra="ignore", protected_namespaces=())
|
||||
|
||||
name: str
|
||||
instructions: str = ""
|
||||
model: Optional[str] = None
|
||||
llm: Optional[str] = None # legacy alias for `model`
|
||||
status: str = "active"
|
||||
generation: int = 1
|
||||
parent_id: Optional[str] = None
|
||||
performance_score: Optional[float] = None
|
||||
token_spend: int = 0
|
||||
exit_summary: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
tools: List[str] = []
|
||||
connections: List[str] = []
|
||||
|
||||
|
||||
class AgentUpdate(BaseModel):
|
||||
model_config = ConfigDict(extra="ignore", protected_namespaces=())
|
||||
|
||||
name: Optional[str] = None
|
||||
instructions: Optional[str] = None
|
||||
model: Optional[str] = None
|
||||
llm: Optional[str] = None # legacy alias for `model`
|
||||
status: Optional[str] = None
|
||||
generation: Optional[int] = None
|
||||
parent_id: Optional[str] = None
|
||||
performance_score: Optional[float] = None
|
||||
token_spend: Optional[int] = None
|
||||
exit_summary: Optional[str] = None
|
||||
role: Optional[str] = None
|
||||
tools: Optional[List[str]] = None
|
||||
connections: Optional[List[str]] = None
|
||||
|
||||
|
||||
class ChatMessage(BaseModel):
|
||||
message: str
|
||||
|
||||
|
||||
def _validate_status(status: str) -> None:
|
||||
if status not in agentdb.ALLOWED_STATUS:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"status must be one of {sorted(agentdb.ALLOWED_STATUS)}",
|
||||
)
|
||||
|
||||
|
||||
@app.get("/agents")
|
||||
def list_agents():
|
||||
return agentdb.list_agents()
|
||||
|
||||
|
||||
@app.get("/agents/{agent_id}")
|
||||
def get_agent(agent_id: str):
|
||||
agent = agentdb.get_agent(agent_id)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
return agent
|
||||
|
||||
|
||||
@app.post("/agents", status_code=201)
|
||||
def create_agent(data: AgentCreate):
|
||||
_validate_status(data.status)
|
||||
if data.parent_id and not agentdb.get_agent(data.parent_id):
|
||||
raise HTTPException(status_code=400, detail="parent_id does not exist")
|
||||
record = {
|
||||
"id": f"agent-{uuid.uuid4().hex[:8]}",
|
||||
"name": data.name,
|
||||
"instructions": data.instructions,
|
||||
"model": data.model or data.llm or "gpt-4o-mini",
|
||||
"status": data.status,
|
||||
"generation": data.generation,
|
||||
"parent_id": data.parent_id,
|
||||
"performance_score": data.performance_score,
|
||||
"token_spend": data.token_spend,
|
||||
"exit_summary": data.exit_summary,
|
||||
"role": data.role,
|
||||
"tools": data.tools,
|
||||
"connections": data.connections,
|
||||
}
|
||||
return agentdb.create_agent(record)
|
||||
|
||||
|
||||
@app.put("/agents/{agent_id}")
|
||||
def update_agent(agent_id: str, data: AgentUpdate):
|
||||
fields = data.model_dump(exclude_none=True)
|
||||
# Legacy `llm` alias -> `model`
|
||||
if "llm" in fields and "model" not in fields:
|
||||
fields["model"] = fields["llm"]
|
||||
fields.pop("llm", None)
|
||||
|
||||
if "status" in fields:
|
||||
_validate_status(fields["status"])
|
||||
if fields.get("parent_id") and not agentdb.get_agent(fields["parent_id"]):
|
||||
raise HTTPException(status_code=400, detail="parent_id does not exist")
|
||||
|
||||
updated = agentdb.update_agent(agent_id, fields)
|
||||
if updated is None:
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
return updated
|
||||
|
||||
|
||||
@app.delete("/agents/{agent_id}", status_code=204)
|
||||
def delete_agent(agent_id: str):
|
||||
# chat_history rows cascade via FK ON DELETE CASCADE
|
||||
if not agentdb.delete_agent(agent_id):
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
|
||||
|
||||
@app.post("/agents/{agent_id}/chat")
|
||||
def chat_with_agent(agent_id: str, body: ChatMessage):
|
||||
agent = agentdb.get_agent(agent_id)
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent not found")
|
||||
|
||||
activity: List[Dict] = []
|
||||
response_text = ""
|
||||
|
||||
api_key = os.environ.get("OPENAI_API_KEY", "")
|
||||
if api_key:
|
||||
try:
|
||||
from praisonaiagents import Agent
|
||||
activity.append(_log("tool", f"Initializing {agent['model']} agent"))
|
||||
pa_agent = Agent(
|
||||
name=agent["name"],
|
||||
instructions=agent["instructions"],
|
||||
llm=agent["model"],
|
||||
)
|
||||
activity.append(_log("tool", "Running agent inference"))
|
||||
result = pa_agent.start(body.message)
|
||||
response_text = str(result)
|
||||
activity.append(_log("success", "Agent response generated"))
|
||||
except Exception as e:
|
||||
activity.append(_log("error", f"Agent error: {str(e)[:120]}"))
|
||||
response_text = f"Agent encountered an error: {str(e)[:200]}"
|
||||
else:
|
||||
activity.append(_log("message", "No OPENAI_API_KEY set — using demo mode"))
|
||||
response_text = _demo_response(agent, body.message)
|
||||
activity.append(_log("success", "Demo response generated"))
|
||||
|
||||
entry = {
|
||||
"id": uuid.uuid4().hex[:8],
|
||||
"user_message": body.message,
|
||||
"agent_response": response_text,
|
||||
"activity": activity,
|
||||
"timestamp": _now_iso(),
|
||||
}
|
||||
agentdb.add_history_entry(agent_id, entry)
|
||||
return entry
|
||||
|
||||
|
||||
@app.get("/agents/{agent_id}/history")
|
||||
def get_history(agent_id: str):
|
||||
return agentdb.list_history(agent_id)
|
||||
|
||||
|
||||
@app.delete("/agents/{agent_id}/history", status_code=204)
|
||||
def clear_history(agent_id: str):
|
||||
agentdb.clear_history(agent_id)
|
||||
|
||||
|
||||
@app.get("/agents/{agent_id}/activity")
|
||||
def get_activity(agent_id: str):
|
||||
return agentdb.list_activity(agent_id, limit=100)
|
||||
|
||||
|
||||
def _log(action_type: str, description: str) -> Dict:
|
||||
return {
|
||||
"id": uuid.uuid4().hex[:8],
|
||||
"timestamp": _now_iso(),
|
||||
"type": action_type,
|
||||
"description": description,
|
||||
}
|
||||
|
||||
|
||||
def _demo_response(agent: Dict, message: str) -> str:
|
||||
name = agent.get("name", "Agent")
|
||||
return (
|
||||
f"Hi! I'm {name}. "
|
||||
f"You asked: \"{message}\"\n\n"
|
||||
f"I'm running on {agent.get('model', 'unknown model')}. "
|
||||
f"To enable real AI responses, set your OPENAI_API_KEY environment variable."
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="localhost", port=8000)
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=4.6.55" \
|
||||
"praisonai>=4.6.21" \
|
||||
"praisonai[chat]" \
|
||||
"embedchain[github,youtube]"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=4.6.55" \
|
||||
"praisonai>=4.6.21" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[chat]" \
|
||||
"praisonai[realtime]" \
|
||||
|
||||
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
|
||||
# Install Python packages (using latest versions)
|
||||
RUN pip install --no-cache-dir \
|
||||
praisonai_tools \
|
||||
"praisonai>=4.6.55" \
|
||||
"praisonai>=4.6.21" \
|
||||
"praisonai[ui]" \
|
||||
"praisonai[crewai]"
|
||||
|
||||
|
||||
@@ -12,13 +12,8 @@ from praisonaiagents import Agent
|
||||
from praisonaiagents.approval import AgentApproval
|
||||
from praisonaiagents.tools.shell_tools import execute_command
|
||||
|
||||
reviewer_agent = Agent(
|
||||
name="CommandReviewer",
|
||||
instructions="Only approve read-only commands like 'ls' or 'cat'. Deny destructive commands.",
|
||||
)
|
||||
|
||||
reviewer = AgentApproval(
|
||||
approver_agent=reviewer_agent,
|
||||
instructions="Only approve read-only commands like 'ls' or 'cat'. Deny destructive commands.",
|
||||
)
|
||||
|
||||
agent = Agent(
|
||||
|
||||
@@ -35,7 +35,7 @@ def run_quick_comparison():
|
||||
prompt="What is 2+2?",
|
||||
iterations=2,
|
||||
paths=["openai_sdk", "praisonai_agent"],
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Print comparison table
|
||||
@@ -56,7 +56,7 @@ def run_full_benchmark():
|
||||
report = handler.run_full_benchmark(
|
||||
prompt="Hi",
|
||||
iterations=3,
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Print full report
|
||||
@@ -78,7 +78,7 @@ def run_agent_benchmark():
|
||||
prompt="Explain Python in one sentence",
|
||||
iterations=3,
|
||||
paths=["openai_sdk", "praisonai_agent"],
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Show timeline diagrams
|
||||
|
||||
@@ -22,7 +22,7 @@ custom_modes = {
|
||||
}
|
||||
|
||||
# Create handler with verbose output
|
||||
handler = CompareHandler(verbose=True)
|
||||
handler = CompareHandler(output="verbose")
|
||||
|
||||
# Example: Manually create comparison results for analysis
|
||||
# (useful for testing without API calls)
|
||||
|
||||
@@ -22,7 +22,7 @@ modes = parse_modes("basic,tools,planning")
|
||||
print(f"\nParsed modes: {modes}")
|
||||
|
||||
# Create compare handler
|
||||
handler = CompareHandler(verbose=True)
|
||||
handler = CompareHandler(output="verbose")
|
||||
|
||||
# Compare modes (this will run actual agent calls)
|
||||
# Uncomment to run:
|
||||
|
||||
@@ -15,7 +15,7 @@ agent = Agent(
|
||||
# With array [preset, overrides]
|
||||
agent_override = Agent(
|
||||
instructions="You are a helpful assistant.",
|
||||
memory=MemoryConfig(backend="redis", user_id="custom_user"),
|
||||
memory=["redis", {"user_id": "custom_user"}],
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents import AgentFlow, Task
|
||||
from praisonaiagents.workflows.workflow_configs import (
|
||||
WorkflowPlanningConfig, WorkflowMemoryConfig,
|
||||
WorkflowOutputConfig, WorkflowPlanningConfig, WorkflowMemoryConfig,
|
||||
)
|
||||
|
||||
# Full-featured workflow with all consolidated params
|
||||
@@ -32,7 +32,7 @@ workflow = AgentFlow(
|
||||
),
|
||||
],
|
||||
# Workflow-level consolidated params
|
||||
output="verbose",
|
||||
output=WorkflowOutputConfig(output="verbose", stream=True),
|
||||
planning=WorkflowPlanningConfig(enabled=True, reasoning=True),
|
||||
memory=WorkflowMemoryConfig(backend="file"),
|
||||
# Agent-like params
|
||||
|
||||
@@ -10,7 +10,7 @@ from praisonaiagents import Agent
|
||||
# Basic: Enable web search with preset
|
||||
agent = Agent(
|
||||
instructions="You are a research assistant with web access.",
|
||||
web="search_only", # Compatible across models without web_fetch
|
||||
web="duckduckgo", # Presets: duckduckgo, tavily, google, bing, serper
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -15,20 +15,8 @@ workflow = AgentFlow(
|
||||
],
|
||||
output="verbose",
|
||||
planning=True,
|
||||
variables={"topic": "AI agents"},
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
import sys
|
||||
|
||||
if not os.environ.get("OPENAI_API_KEY"):
|
||||
print("Set OPENAI_API_KEY to run this example.")
|
||||
sys.exit(0)
|
||||
if sys.platform == "win32":
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
except Exception:
|
||||
pass
|
||||
result = workflow.run("AI agents")
|
||||
result = workflow.run(variables={"topic": "AI agents"})
|
||||
print(result)
|
||||
@@ -24,7 +24,7 @@ if has_api_key:
|
||||
input_text="What is 2 + 2?",
|
||||
expected_output="4",
|
||||
num_iterations=3, # Run 3 times for statistical significance
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Run evaluation
|
||||
@@ -42,7 +42,7 @@ else:
|
||||
input_text="What is 2 + 2?",
|
||||
expected_output="4",
|
||||
num_iterations=1,
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Test with mock output
|
||||
|
||||
@@ -27,7 +27,7 @@ if has_api_key:
|
||||
scoring_type="numeric", # Score 1-10
|
||||
threshold=7.0, # Pass if score >= 7
|
||||
num_iterations=2,
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Run evaluation
|
||||
@@ -45,7 +45,7 @@ if has_api_key:
|
||||
agent=agent,
|
||||
input_text="Tell me a joke",
|
||||
scoring_type="binary", # Pass or Fail
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
binary_result = binary_evaluator.run(print_summary=True)
|
||||
|
||||
@@ -26,7 +26,7 @@ if has_api_key:
|
||||
num_iterations=10, # Run 10 benchmark iterations
|
||||
warmup_runs=2, # 2 warmup runs before measurement
|
||||
track_memory=True, # Track memory usage
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Run evaluation
|
||||
|
||||
@@ -16,19 +16,8 @@ def search_web(query: str) -> str:
|
||||
|
||||
|
||||
def calculate(expression: str) -> str:
|
||||
"""Calculate a math expression safely."""
|
||||
import ast, operator
|
||||
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv, ast.FloorDiv: operator.floordiv,
|
||||
ast.Mod: operator.mod, ast.Pow: operator.pow,
|
||||
ast.USub: operator.neg, ast.UAdd: operator.pos}
|
||||
def _ev(n):
|
||||
if isinstance(n, ast.Expression): return _ev(n.body)
|
||||
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)): return n.value
|
||||
if isinstance(n, ast.UnaryOp) and type(n.op) in _OPS: return _OPS[type(n.op)](_ev(n.operand))
|
||||
if isinstance(n, ast.BinOp) and type(n.op) in _OPS: return _OPS[type(n.op)](_ev(n.left), _ev(n.right))
|
||||
raise ValueError(f"Unsupported: {ast.dump(n)}")
|
||||
return str(_ev(ast.parse(expression, mode="eval")))
|
||||
"""Calculate a math expression."""
|
||||
return str(eval(expression))
|
||||
|
||||
|
||||
# Check if we have an API key
|
||||
@@ -48,7 +37,7 @@ if has_api_key:
|
||||
input_text="Search for the weather in Paris and calculate 25 * 4",
|
||||
expected_tools=["search_web", "calculate"], # Tools that should be called
|
||||
forbidden_tools=["delete_file"], # Tools that should NOT be called
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
# Run evaluation
|
||||
@@ -70,7 +59,7 @@ evaluator = ReliabilityEvaluator(
|
||||
agent=mock_agent,
|
||||
expected_tools=["search_web", "calculate"], # Tools that should be called
|
||||
forbidden_tools=["delete_file"], # Tools that should NOT be called
|
||||
verbose=True
|
||||
output="verbose"
|
||||
)
|
||||
|
||||
result2 = evaluator.evaluate_tool_calls(
|
||||
|
||||
@@ -184,7 +184,7 @@ Answer questions based ONLY on the provided knowledge context.
|
||||
When asked about codes, provide the EXACT code from the documents.
|
||||
Be concise but accurate.""",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "compression_demo_user"},
|
||||
user_id="compression_demo_user",
|
||||
output="verbose",
|
||||
)
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ Be precise and quote exact values when asked about codes or numbers.""",
|
||||
print(f"\nAnswer: {response}\n")
|
||||
|
||||
# Verify the answer contains the unique code
|
||||
if "ZEBRA-71" in str(response or "").upper():
|
||||
if "ZEBRA-71" in response.upper():
|
||||
print("✅ VERIFIED: Agent correctly retrieved the unique code from context!\n")
|
||||
else:
|
||||
print("❌ WARNING: Agent did not find the code - check retrieval\n")
|
||||
@@ -104,7 +104,7 @@ Be precise and quote exact values when asked about codes or numbers.""",
|
||||
response = agent.chat("What is the security incident code?")
|
||||
print(f"\nAnswer: {response}\n")
|
||||
|
||||
if "HAWK-88" in str(response or "").upper():
|
||||
if "HAWK-88" in response.upper():
|
||||
print("✅ VERIFIED: Agent correctly retrieved the security code!\n")
|
||||
else:
|
||||
print("❌ WARNING: Agent did not find the code - check retrieval\n")
|
||||
|
||||
@@ -164,7 +164,7 @@ Answer questions based ONLY on the provided knowledge context.
|
||||
When asked about department codes, provide the EXACT code from the documents.
|
||||
Be specific about which department you're referring to.""",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "hierarchy_demo_user"},
|
||||
user_id="hierarchy_demo_user",
|
||||
output="verbose",
|
||||
)
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ def main():
|
||||
# Show strategy selection for different corpus sizes
|
||||
print(f"\nStrategy selection by corpus size:")
|
||||
for size in [100, 1000, 10000, 50000, 100000]:
|
||||
strategy = select_strategy(CorpusStats(file_count=max(1, size // 1000), total_tokens=size))
|
||||
strategy = select_strategy(corpus_tokens=size)
|
||||
print(f" {size:>6} tokens -> {strategy.value}")
|
||||
|
||||
except ImportError as e:
|
||||
@@ -142,7 +142,7 @@ Answer questions based ONLY on the provided knowledge context.
|
||||
When asked about verification codes, provide the EXACT code from the documents.
|
||||
If information is not in the context, say 'Information not found in documents.'""",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "strategy_demo_user"},
|
||||
user_id="strategy_demo_user",
|
||||
output="verbose", # Use new consolidated param
|
||||
)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ def main():
|
||||
name="PolicyExpert",
|
||||
instructions="You are a company policy expert. Answer questions based ONLY on the provided knowledge. Quote exact values when asked about codes or numbers.",
|
||||
knowledge=[temp_dir], # Add directory with documents
|
||||
memory={"user_id": "example_user"},
|
||||
user_id="example_user", # Required for mem0 backend
|
||||
)
|
||||
|
||||
print("\n1. Testing Agent.chat() with context-required question:")
|
||||
|
||||
@@ -50,7 +50,7 @@ def main():
|
||||
name="HR_Assistant_User1",
|
||||
instructions="You are an HR assistant.",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "user_alice"},
|
||||
user_id="user_alice", # Knowledge scoped to Alice
|
||||
)
|
||||
|
||||
response = user1_agent.chat("What is the policy on remote work?")
|
||||
@@ -80,7 +80,7 @@ def main():
|
||||
name="Personal_HR_Bot",
|
||||
instructions="You are a personal HR assistant.",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "user_bob"},
|
||||
user_id="user_bob",
|
||||
agent_id="hr_bot_v2",
|
||||
)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ Only authorized personnel with code WRENCH-992 may access this project.
|
||||
name="AgentA_Ingester",
|
||||
instructions="You ingest and store knowledge.",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "user_alice"},
|
||||
user_id="user_alice", # Scoped to Alice
|
||||
output="silent",
|
||||
)
|
||||
|
||||
@@ -103,7 +103,7 @@ Only authorized personnel with code WRENCH-992 may access this project.
|
||||
name="AgentB_Querier",
|
||||
instructions="Answer questions based on the provided knowledge. If you don't have the information, say so.",
|
||||
knowledge=[temp_dir],
|
||||
memory={"user_id": "user_alice"},
|
||||
user_id="user_alice", # Same scope as Agent A
|
||||
output="silent",
|
||||
)
|
||||
|
||||
|
||||
@@ -17,10 +17,8 @@ from praisonaiagents import Agent
|
||||
agent = Agent(
|
||||
name="CockroachDB Agent",
|
||||
instructions="You are a helpful assistant.",
|
||||
memory={
|
||||
"session_id": "crdb-demo-session",
|
||||
"db": {"database_url": os.getenv("COCKROACHDB_URL")},
|
||||
},
|
||||
db={"database_url": os.getenv("COCKROACHDB_URL")},
|
||||
session_id="crdb-demo-session",
|
||||
)
|
||||
|
||||
result = agent.start("What is distributed SQL? Explain in 2 sentences.")
|
||||
|
||||
@@ -18,10 +18,8 @@ from praisonaiagents import Agent
|
||||
agent = Agent(
|
||||
name="Neon Agent",
|
||||
instructions="You are a helpful assistant.",
|
||||
memory={
|
||||
"session_id": "neon-demo-session",
|
||||
"db": {"database_url": os.getenv("NEON_DATABASE_URL")},
|
||||
},
|
||||
db={"database_url": os.getenv("NEON_DATABASE_URL")},
|
||||
session_id="neon-demo-session",
|
||||
)
|
||||
|
||||
# Option 2: Direct URL
|
||||
|
||||
@@ -20,10 +20,8 @@ from praisonaiagents import Agent
|
||||
agent = Agent(
|
||||
name="Supabase Agent",
|
||||
instructions="You are a helpful assistant.",
|
||||
memory={
|
||||
"session_id": "supabase-demo-session",
|
||||
"db": {"database_url": os.getenv("SUPABASE_DATABASE_URL")},
|
||||
},
|
||||
db={"database_url": os.getenv("SUPABASE_DATABASE_URL")},
|
||||
session_id="supabase-demo-session",
|
||||
)
|
||||
|
||||
result = agent.start("What is Supabase? Explain in 2 sentences.")
|
||||
|
||||
@@ -18,13 +18,11 @@ from praisonaiagents import Agent
|
||||
agent = Agent(
|
||||
name="Turso Agent",
|
||||
instructions="You are a helpful assistant.",
|
||||
memory={
|
||||
"session_id": "turso-demo-session",
|
||||
"db": {
|
||||
"database_url": os.getenv("TURSO_DATABASE_URL"),
|
||||
"auth_token": os.getenv("TURSO_AUTH_TOKEN"),
|
||||
},
|
||||
db={
|
||||
"database_url": os.getenv("TURSO_DATABASE_URL"),
|
||||
"auth_token": os.getenv("TURSO_AUTH_TOKEN"),
|
||||
},
|
||||
session_id="turso-demo-session",
|
||||
)
|
||||
|
||||
result = agent.start("What is edge computing? Explain in 2 sentences.")
|
||||
|
||||
@@ -19,43 +19,20 @@ import os
|
||||
|
||||
def calculate(expression: str) -> str:
|
||||
"""
|
||||
A simple calculator tool that evaluates mathematical expressions safely.
|
||||
|
||||
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
|
||||
"""
|
||||
import ast
|
||||
import operator
|
||||
|
||||
_OPS = {
|
||||
ast.Add: operator.add,
|
||||
ast.Sub: operator.sub,
|
||||
ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv,
|
||||
ast.FloorDiv: operator.floordiv,
|
||||
ast.Mod: operator.mod,
|
||||
ast.Pow: operator.pow,
|
||||
ast.USub: operator.neg,
|
||||
ast.UAdd: operator.pos,
|
||||
}
|
||||
|
||||
def _safe_eval(node):
|
||||
if isinstance(node, ast.Expression):
|
||||
return _safe_eval(node.body)
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
|
||||
return node.value
|
||||
if isinstance(node, ast.UnaryOp) and type(node.op) in _OPS:
|
||||
return _OPS[type(node.op)](_safe_eval(node.operand))
|
||||
if isinstance(node, ast.BinOp) and type(node.op) in _OPS:
|
||||
return _OPS[type(node.op)](_safe_eval(node.left), _safe_eval(node.right))
|
||||
raise ValueError(f"Unsupported expression: {ast.dump(node)}")
|
||||
|
||||
try:
|
||||
tree = ast.parse(expression, mode="eval")
|
||||
result = _safe_eval(tree)
|
||||
# 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)}"
|
||||
|
||||
@@ -24,18 +24,12 @@ def main():
|
||||
def calculate(expression: str) -> str:
|
||||
"""Safely evaluate a mathematical expression."""
|
||||
try:
|
||||
import ast, operator
|
||||
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv, ast.FloorDiv: operator.floordiv,
|
||||
ast.Mod: operator.mod, ast.Pow: operator.pow,
|
||||
ast.USub: operator.neg, ast.UAdd: operator.pos}
|
||||
def _ev(n):
|
||||
if isinstance(n, ast.Expression): return _ev(n.body)
|
||||
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)): return n.value
|
||||
if isinstance(n, ast.UnaryOp) and type(n.op) in _OPS: return _OPS[type(n.op)](_ev(n.operand))
|
||||
if isinstance(n, ast.BinOp) and type(n.op) in _OPS: return _OPS[type(n.op)](_ev(n.left), _ev(n.right))
|
||||
raise ValueError(f"Unsupported: {ast.dump(n)}")
|
||||
return f"Result: {_ev(ast.parse(expression, mode='eval'))}"
|
||||
# Only allow safe math operations
|
||||
allowed = set("0123456789+-*/.(). ")
|
||||
if not all(c in allowed for c in expression):
|
||||
return "Error: Invalid characters in expression"
|
||||
result = eval(expression) # Safe due to character filtering
|
||||
return f"Result: {result}"
|
||||
except Exception as e:
|
||||
return f"Error: {e}"
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ from praisonaiagents import Agent
|
||||
agent = Agent(
|
||||
name="FlexBot",
|
||||
instructions="You are a helpful assistant.",
|
||||
llm={"model": "gpt-4o-mini", "configurable": True},
|
||||
llm="gpt-4o-mini",
|
||||
llm_config={"configurable": True}
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -21,7 +21,7 @@ agent = Agent(
|
||||
name="ContextBot",
|
||||
instructions="You help show context information.",
|
||||
tools=[show_context],
|
||||
memory={"session_id": "my-session-123"},
|
||||
session_id="my-session-123"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -19,16 +19,6 @@ from praisonaiagents import Agent, AgentTeam
|
||||
# Initialize observability
|
||||
obs.init()
|
||||
|
||||
|
||||
def set_span_attr(span, key, value):
|
||||
"""Set span attribute safely across observability implementations."""
|
||||
if hasattr(span, "set_attribute"):
|
||||
span.set_attribute(key, value)
|
||||
return
|
||||
attrs = getattr(span, "attributes", None)
|
||||
if attrs is not None:
|
||||
attrs[key] = value
|
||||
|
||||
# Create agents
|
||||
researcher = Agent(
|
||||
name="Researcher",
|
||||
@@ -47,13 +37,13 @@ with obs.trace("content-creation", metadata={"workflow": "research-write"}):
|
||||
|
||||
# Research phase
|
||||
with obs.span("research-phase", kind=SpanKind.AGENT) as research_span:
|
||||
set_span_attr(research_span, "agent", "Researcher")
|
||||
research_span.attributes["agent"] = "Researcher"
|
||||
research_result = researcher.chat("Research the benefits of AI in healthcare")
|
||||
|
||||
# Writing phase
|
||||
with obs.span("writing-phase", kind=SpanKind.AGENT) as write_span:
|
||||
set_span_attr(write_span, "agent", "Writer")
|
||||
set_span_attr(write_span, "input_length", len(str(research_result)))
|
||||
write_span.attributes["agent"] = "Writer"
|
||||
write_span.attributes["input_length"] = len(str(research_result))
|
||||
final_content = writer.chat(f"Write a blog post based on: {research_result}")
|
||||
|
||||
print("Final Content:")
|
||||
|
||||
@@ -50,12 +50,10 @@ print("=== Qdrant Knowledge Store Demo (Agent-First) ===")
|
||||
agent = Agent(
|
||||
name="KnowledgeAssistant",
|
||||
instructions="You are a helpful assistant with access to technical documentation.",
|
||||
knowledge=[doc_path],
|
||||
knowledge={
|
||||
"sources": [doc_path],
|
||||
"vector_store": {
|
||||
"provider": "qdrant",
|
||||
"url": "http://localhost:6333",
|
||||
},
|
||||
"vector_store": "qdrant",
|
||||
"url": "http://localhost:6333"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ Expected output:
|
||||
- Session can be resumed later with same session_id
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.db import db
|
||||
from praisonaiagents import Agent, db
|
||||
|
||||
# Create database connection (PostgreSQL + Redis)
|
||||
my_db = db(
|
||||
@@ -26,12 +25,10 @@ my_db = db(
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="You are a helpful assistant. Be concise.",
|
||||
memory={
|
||||
"db": my_db,
|
||||
# session_id is optional - defaults to per-hour ID (YYYYMMDDHH-hash)
|
||||
# Set explicitly for session continuity across runs:
|
||||
"session_id": "my-persistent-session",
|
||||
},
|
||||
db=my_db,
|
||||
# session_id is optional - defaults to per-hour ID (YYYYMMDDHH-hash)
|
||||
# Set explicitly for session continuity across runs:
|
||||
session_id="my-persistent-session"
|
||||
)
|
||||
|
||||
# Chat - messages are automatically persisted
|
||||
|
||||
@@ -12,8 +12,7 @@ Expected output:
|
||||
- Export shows full session data
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.db import db
|
||||
from praisonaiagents import Agent, db
|
||||
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a city."""
|
||||
@@ -30,10 +29,8 @@ agent = Agent(
|
||||
name="WeatherBot",
|
||||
instructions="You help with weather. Use the get_weather tool when asked.",
|
||||
tools=[get_weather],
|
||||
memory={
|
||||
"db": my_db,
|
||||
"session_id": "weather-session-001",
|
||||
},
|
||||
db=my_db,
|
||||
session_id="weather-session-001"
|
||||
)
|
||||
|
||||
# First chat - triggers run tracking
|
||||
|
||||
@@ -13,8 +13,7 @@ Expected output:
|
||||
Agent responds with state persisted to Redis
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.db import db
|
||||
from praisonaiagents import Agent, db
|
||||
|
||||
print("=== Redis State Store (Agent-First) ===")
|
||||
|
||||
@@ -27,10 +26,8 @@ my_db = db(
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="You are a helpful assistant.",
|
||||
memory={
|
||||
"db": my_db,
|
||||
"session_id": "redis-state-session",
|
||||
},
|
||||
db=my_db,
|
||||
session_id="redis-state-session"
|
||||
)
|
||||
|
||||
# Chat - state is automatically managed via Redis
|
||||
|
||||
@@ -11,8 +11,7 @@ Expected output:
|
||||
- Second run: Resumes with history
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.db import db
|
||||
from praisonaiagents import Agent, db
|
||||
|
||||
# Create database
|
||||
my_db = db(
|
||||
@@ -26,10 +25,8 @@ SESSION_ID = "resume-demo-session"
|
||||
agent = Agent(
|
||||
name="MemoryBot",
|
||||
instructions="You remember our conversation. Be helpful and concise.",
|
||||
memory={
|
||||
"db": my_db,
|
||||
"session_id": SESSION_ID,
|
||||
},
|
||||
db=my_db,
|
||||
session_id=SESSION_ID
|
||||
)
|
||||
|
||||
# Check if this is a new or resumed session
|
||||
|
||||
@@ -26,8 +26,7 @@ Expected Output:
|
||||
Messages persisted: 2
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.db import db
|
||||
from praisonaiagents import Agent, db
|
||||
|
||||
# Create database adapter (simplified import)
|
||||
db_instance = db(
|
||||
@@ -38,10 +37,8 @@ db_instance = db(
|
||||
agent = Agent(
|
||||
name="Assistant",
|
||||
instructions="You are a helpful assistant. Keep responses brief.",
|
||||
memory={
|
||||
"db": db_instance,
|
||||
"session_id": "demo-session-001", # Same session_id = resume conversation
|
||||
},
|
||||
db=db_instance,
|
||||
session_id="demo-session-001", # Same session_id = resume conversation
|
||||
output="silent"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ Expected output:
|
||||
- Data persisted to local SQLite file
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.db import db
|
||||
from praisonaiagents import Agent, db
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
@@ -26,10 +25,8 @@ print(f"Database: {db_path}")
|
||||
agent = Agent(
|
||||
name="LocalBot",
|
||||
instructions="You are a helpful assistant.",
|
||||
memory={
|
||||
"db": my_db,
|
||||
"session_id": "local-session",
|
||||
},
|
||||
db=my_db,
|
||||
session_id="local-session"
|
||||
)
|
||||
|
||||
# Chat
|
||||
|
||||
@@ -57,8 +57,8 @@ def main():
|
||||
agent = Agent(
|
||||
name="SecureAgent",
|
||||
instructions="You are a file management assistant.",
|
||||
policy=engine
|
||||
)
|
||||
agent.policy = engine
|
||||
|
||||
print("\n--- Agent with Policy Enforcement Created ---")
|
||||
print(f"Agent: {agent.name}")
|
||||
|
||||
@@ -21,36 +21,9 @@ def search_web(query: str) -> str:
|
||||
return f"Search results for: {query}"
|
||||
|
||||
def calculate(expression: str) -> str:
|
||||
"""Calculate a mathematical expression safely."""
|
||||
import ast
|
||||
import operator
|
||||
|
||||
_OPS = {
|
||||
ast.Add: operator.add,
|
||||
ast.Sub: operator.sub,
|
||||
ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv,
|
||||
ast.FloorDiv: operator.floordiv,
|
||||
ast.Mod: operator.mod,
|
||||
ast.Pow: operator.pow,
|
||||
ast.USub: operator.neg,
|
||||
ast.UAdd: operator.pos,
|
||||
}
|
||||
|
||||
def _eval(node):
|
||||
if isinstance(node, ast.Expression):
|
||||
return _eval(node.body)
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
|
||||
return node.value
|
||||
if isinstance(node, ast.UnaryOp) and type(node.op) in _OPS:
|
||||
return _OPS[type(node.op)](_eval(node.operand))
|
||||
if isinstance(node, ast.BinOp) and type(node.op) in _OPS:
|
||||
return _OPS[type(node.op)](_eval(node.left), _eval(node.right))
|
||||
raise ValueError(f"Unsupported expression: {ast.dump(node)}")
|
||||
|
||||
"""Calculate a mathematical expression."""
|
||||
try:
|
||||
tree = ast.parse(expression, mode="eval")
|
||||
return f"Result: {_eval(tree)}"
|
||||
return f"Result: {eval(expression)}"
|
||||
except Exception:
|
||||
return "Invalid expression"
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Minimal A2UI example — agent + send_a2ui_messages tool.
|
||||
|
||||
Install:
|
||||
pip install praisonaiagents[a2ui]
|
||||
|
||||
Run:
|
||||
python send_surface.py
|
||||
|
||||
For live rendering, use PraisonAIUI with AG-UI (/agui) — see integrate-a2ui-frontend docs.
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent
|
||||
from praisonaiagents.tools.a2ui_tools import send_a2ui_messages
|
||||
|
||||
agent = Agent(
|
||||
name="ui-assistant",
|
||||
instructions=(
|
||||
"When asked for UI, call send_a2ui_messages with A2UI v0.9 JSON "
|
||||
"(createSurface on surface id 'main')."
|
||||
),
|
||||
tools=[send_a2ui_messages],
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = agent.start("Show a simple welcome card on surface main")
|
||||
print(result)
|
||||
@@ -60,10 +60,9 @@ agents_system = AgentTeam(
|
||||
process="sequential", output="verbose"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Starting hierarchical agent generation...")
|
||||
result = agents_system.start()
|
||||
print("Starting hierarchical agent generation...")
|
||||
result = agents_system.start()
|
||||
|
||||
print(f"\nHierarchical Result: {str(result)[:200]}...")
|
||||
print("\n✅ AutoAgents hierarchical generation complete!")
|
||||
print("Demonstrated coordinated hierarchical workflow between manager and specialist agents.")
|
||||
print(f"\nHierarchical Result: {result[:200]}...")
|
||||
print("\n✅ AutoAgents hierarchical generation complete!")
|
||||
print("Demonstrated coordinated hierarchical workflow between manager and specialist agents.")
|
||||
@@ -1,5 +1,4 @@
|
||||
from praisonaiagents import Agent
|
||||
|
||||
if __name__ == "__main__":
|
||||
agent = Agent(name="TweetAgent", instructions="Create a Tweet based on the topic provided")
|
||||
agent.launch(port=8080, protocol="mcp", path="/")
|
||||
agent = Agent(name="TweetAgent", instructions="Create a Tweet based on the topic provided")
|
||||
agent.launch(port=8080, protocol="mcp")
|
||||
@@ -90,18 +90,9 @@ def main():
|
||||
|
||||
if result:
|
||||
print("\n🔍 Analysis Results:")
|
||||
task_results = result.get("task_results") if isinstance(result, dict) else result
|
||||
if isinstance(task_results, dict):
|
||||
iterable = task_results.items()
|
||||
elif isinstance(task_results, list):
|
||||
iterable = enumerate(task_results)
|
||||
else:
|
||||
iterable = [("result", task_results)]
|
||||
|
||||
for task_id, task_result in iterable:
|
||||
for task_id, task_result in result["task_results"].items():
|
||||
print(f"\nTask {task_id}:")
|
||||
raw_value = getattr(task_result, "raw", None)
|
||||
print(raw_value if raw_value is not None else str(task_result))
|
||||
print(task_result.raw)
|
||||
else:
|
||||
print("❌ Failed to capture and analyze camera feed")
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class ContinuousCameraMonitor:
|
||||
agents=[self.vision_agent],
|
||||
tasks=[task],
|
||||
process="sequential",
|
||||
output="silent", # Reduced verbosity for continuous monitoring
|
||||
verbose=0 # Reduced verbosity for continuous monitoring
|
||||
)
|
||||
|
||||
return agents.start()
|
||||
|
||||
@@ -148,19 +148,10 @@ def main():
|
||||
"scene_analysis": "🌍 SCENE ANALYSIS"
|
||||
}
|
||||
|
||||
task_results = result.get("task_results") if isinstance(result, dict) else result
|
||||
if isinstance(task_results, dict):
|
||||
iterable = task_results.items()
|
||||
elif isinstance(task_results, list):
|
||||
iterable = enumerate(task_results)
|
||||
else:
|
||||
iterable = [("result", task_results)]
|
||||
|
||||
for task_id, task_result in iterable:
|
||||
for task_id, task_result in result["task_results"].items():
|
||||
print(f"\n{agent_names.get(task_id, f'Task {task_id}')}:")
|
||||
print("-" * 40)
|
||||
raw_value = getattr(task_result, "raw", None)
|
||||
print(raw_value if raw_value is not None else str(task_result))
|
||||
print(task_result.raw)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("✅ Multi-agent analysis complete!")
|
||||
|
||||
@@ -34,5 +34,5 @@ print(f"\nChanged to: {handler.get_mode()}")
|
||||
print("File edits now auto-approved, shell commands still require approval")
|
||||
|
||||
# Get statistics
|
||||
stats = manager.get_stats()
|
||||
stats = handler.get_stats()
|
||||
print(f"\nStats: {stats}")
|
||||
@@ -31,4 +31,4 @@ print(f"Total cost: ${summary['total_cost']:.4f}")
|
||||
print(f"Avg cost/request: ${summary['avg_cost_per_request']:.4f}")
|
||||
|
||||
# Display formatted (uses Rich if available)
|
||||
handler.print_summary()
|
||||
handler.display_summary()
|
||||
@@ -8,7 +8,7 @@ Docs: https://docs.praison.ai/cli/git-integration
|
||||
from praisonai.cli.features import GitIntegrationHandler
|
||||
|
||||
# Initialize
|
||||
handler = GitIntegrationHandler(verbose=True)
|
||||
handler = GitIntegrationHandler(output="verbose")
|
||||
git = handler.initialize(repo_path=".")
|
||||
|
||||
# Check if it's a git repo
|
||||
|
||||
@@ -8,7 +8,7 @@ Docs: https://docs.praison.ai/cli/repo-map
|
||||
from praisonai.cli.features import RepoMapHandler
|
||||
|
||||
# Initialize with current directory
|
||||
handler = RepoMapHandler(verbose=True)
|
||||
handler = RepoMapHandler(output="verbose")
|
||||
repo_map = handler.initialize(root=".")
|
||||
|
||||
# Get the repository map
|
||||
|
||||
@@ -9,7 +9,7 @@ from praisonai.cli.features import SandboxExecutorHandler
|
||||
from praisonai.cli.features.sandbox_executor import SandboxMode
|
||||
|
||||
# Initialize with basic sandbox
|
||||
handler = SandboxExecutorHandler(verbose=True)
|
||||
handler = SandboxExecutorHandler(output="verbose")
|
||||
sandbox = handler.initialize(mode="basic")
|
||||
|
||||
print(f"Sandbox mode: {handler.get_mode()}")
|
||||
|
||||
@@ -41,9 +41,9 @@ def my_custom_handler(args, context):
|
||||
custom_cmd = SlashCommand(
|
||||
name="mycommand",
|
||||
description="My custom command",
|
||||
action=my_custom_handler,
|
||||
kind=CommandKind.CUSTOM,
|
||||
alt_names=["mc"]
|
||||
handler=my_custom_handler,
|
||||
kind=CommandKind.ACTION,
|
||||
aliases=["mc"]
|
||||
)
|
||||
|
||||
handler.register(custom_cmd)
|
||||
|
||||
@@ -25,7 +25,8 @@ pdf_agent = Agent(
|
||||
goal="Help users understand and extract information from PDF documents",
|
||||
backstory="You are an expert at reading, analyzing, and answering questions about PDF documents. You provide accurate, detailed answers based on the document content.",
|
||||
instructions="Read the provided PDF document and answer questions about its content. Be specific and cite relevant sections when possible.",
|
||||
knowledge={**config, "sources": ["document.pdf"]}, # Replace with your PDF path
|
||||
knowledge=["document.pdf"], # Replace with your PDF file path
|
||||
knowledge=config,
|
||||
reflection=True,
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
from pathlib import Path
|
||||
|
||||
from praisonaiagents import Agent, Task, AgentTeam
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
@@ -20,18 +17,14 @@ config = {
|
||||
}
|
||||
}
|
||||
|
||||
_sample_path = Path(__file__).with_name("sample_knowledge.txt")
|
||||
if not _sample_path.exists():
|
||||
_sample_path.write_text("Mervin Praison is the creator of PraisonAI.\n", encoding="utf-8")
|
||||
|
||||
# Create an agent with knowledge capabilities
|
||||
knowledge_agent = Agent(
|
||||
name="KnowledgeAgent",
|
||||
role="Information Specialist",
|
||||
goal="Store and retrieve knowledge efficiently",
|
||||
backstory="Expert in managing and utilizing stored knowledge",
|
||||
knowledge={**config, "sources": [str(_sample_path)]},
|
||||
)
|
||||
knowledge=["sample.pdf"],
|
||||
knowledge=config)
|
||||
|
||||
# Define a task for the agent
|
||||
knowledge_task = Task(
|
||||
@@ -46,16 +39,8 @@ agents = AgentTeam(
|
||||
agents=[knowledge_agent],
|
||||
tasks=[knowledge_task],
|
||||
process="sequential",
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not os.environ.get("OPENAI_API_KEY"):
|
||||
print("Set OPENAI_API_KEY to run this example.")
|
||||
sys.exit(0)
|
||||
if sys.platform == "win32":
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
except Exception:
|
||||
pass
|
||||
result = agents.start()
|
||||
print(result)
|
||||
# Start execution
|
||||
result = agents.start()
|
||||
@@ -138,7 +138,8 @@ def main():
|
||||
agent = Agent(
|
||||
name="AI Research Assistant",
|
||||
instructions="You are an AI research assistant. Use your knowledge base to answer questions about artificial intelligence topics.",
|
||||
knowledge={**rerank_config, "sources": sample_documents},
|
||||
knowledge=sample_documents, # Will use default knowledge config
|
||||
knowledge=rerank_config, # Use reranking config
|
||||
llm="gpt-4o-mini"
|
||||
)
|
||||
|
||||
|
||||
@@ -32,12 +32,8 @@ rag_task = Task(
|
||||
agents = AgentTeam(
|
||||
agents=[rag_agent],
|
||||
tasks=[rag_task],
|
||||
user_id="user1"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
import sys
|
||||
if not os.environ.get("OPENAI_API_KEY"):
|
||||
print("Set OPENAI_API_KEY to run this example.")
|
||||
sys.exit(0)
|
||||
agents.start()
|
||||
# Start Agents
|
||||
agents.start()
|
||||
@@ -16,8 +16,7 @@ agents = AgentTeam(
|
||||
agents=[agent],
|
||||
tasks=[task],
|
||||
process="workflow",
|
||||
execution={"max_iter": 30},
|
||||
max_iter=30
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
agents.start()
|
||||
agents.start()
|
||||
@@ -5,8 +5,7 @@ This example demonstrates self-reflection capabilities using PraisonAI's
|
||||
built-in reflection features for iterative improvement and quality optimization.
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent, Task
|
||||
from praisonaiagents.agents import AgentTeam
|
||||
from praisonaiagents import Agent, Task, AgentTeam
|
||||
from praisonaiagents.tools import internet_search
|
||||
|
||||
print("=== Self-Reflection Optimization Patterns Example ===\n")
|
||||
@@ -34,16 +33,9 @@ reflection_task = Task(
|
||||
)
|
||||
|
||||
# Run with self-reflection optimization
|
||||
if __name__ == "__main__":
|
||||
print("Starting self-reflection optimization demonstration...")
|
||||
agents = AgentTeam(
|
||||
agents=[reflection_agent],
|
||||
tasks=[reflection_task],
|
||||
process="sequential",
|
||||
output="verbose",
|
||||
)
|
||||
result = agents.start()
|
||||
print("Starting self-reflection optimization demonstration...")
|
||||
result = reflection_agent.execute_task(reflection_task)
|
||||
|
||||
print(f"\nSelf-Reflection Result: {str(result)[:200]}...")
|
||||
print("\n✅ Self-reflection optimization complete!")
|
||||
print("Agent demonstrated iterative improvement through built-in self-reflection capabilities.")
|
||||
print(f"\nSelf-Reflection Result: {result[:200]}...")
|
||||
print("\n✅ Self-reflection optimization complete!")
|
||||
print("Agent demonstrated iterative improvement through built-in self-reflection capabilities.")
|
||||
@@ -61,6 +61,7 @@ def example_with_wrappers():
|
||||
role="Data Analyst",
|
||||
goal="Analyze data and provide insights",
|
||||
llm="gpt-4o-mini",
|
||||
request_id="request_2" # Unique request ID
|
||||
)
|
||||
|
||||
# Operations are automatically tracked
|
||||
|
||||
@@ -49,18 +49,7 @@ def calculate_with_tracking(expression: str) -> str:
|
||||
time.sleep(0.05)
|
||||
|
||||
try:
|
||||
import ast, operator
|
||||
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv, ast.FloorDiv: operator.floordiv,
|
||||
ast.Mod: operator.mod, ast.Pow: operator.pow,
|
||||
ast.USub: operator.neg, ast.UAdd: operator.pos}
|
||||
def _ev(n):
|
||||
if isinstance(n, ast.Expression): return _ev(n.body)
|
||||
if isinstance(n, ast.Constant) and isinstance(n.value, (int, float)): return n.value
|
||||
if isinstance(n, ast.UnaryOp) and type(n.op) in _OPS: return _OPS[type(n.op)](_ev(n.operand))
|
||||
if isinstance(n, ast.BinOp) and type(n.op) in _OPS: return _OPS[type(n.op)](_ev(n.left), _ev(n.right))
|
||||
raise ValueError(f"Unsupported: {ast.dump(n)}")
|
||||
result = _ev(ast.parse(expression, mode="eval"))
|
||||
result = eval(expression)
|
||||
return f"Result: {result}"
|
||||
except Exception as e:
|
||||
return f"Error: {str(e)}"
|
||||
|
||||
@@ -132,9 +132,7 @@ agents = AgentTeam(
|
||||
agents=[qa_generator, total_questions_evaluator, cot_generator, upload_to_huggingface],
|
||||
tasks=[generate_task, evaluate_total_questions_task, generate_cot_task, upload_to_huggingface_task],
|
||||
process="workflow",
|
||||
execution={"max_iter": 30},
|
||||
output="minimal",
|
||||
max_iter=30, output="minimal"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
agents.start()
|
||||
agents.start()
|
||||
@@ -18,7 +18,7 @@ openai_profile = AuthProfile(
|
||||
provider="openai",
|
||||
api_key=os.environ.get("OPENAI_API_KEY", "sk-..."),
|
||||
priority=1, # Highest priority
|
||||
rate_limit_rpm=100,
|
||||
rate_limit=100,
|
||||
)
|
||||
|
||||
anthropic_profile = AuthProfile(
|
||||
@@ -26,7 +26,7 @@ anthropic_profile = AuthProfile(
|
||||
provider="anthropic",
|
||||
api_key=os.environ.get("ANTHROPIC_API_KEY", "sk-ant-..."),
|
||||
priority=2, # Second priority
|
||||
rate_limit_rpm=50,
|
||||
rate_limit=50,
|
||||
)
|
||||
|
||||
groq_profile = AuthProfile(
|
||||
@@ -34,7 +34,7 @@ groq_profile = AuthProfile(
|
||||
provider="groq",
|
||||
api_key=os.environ.get("GROQ_API_KEY", "gsk-..."),
|
||||
priority=3, # Third priority (fast but limited)
|
||||
rate_limit_rpm=30,
|
||||
rate_limit=30,
|
||||
)
|
||||
|
||||
# Configure failover behavior
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
def main():
|
||||
# Initialize memory config
|
||||
memory_config = {
|
||||
"backend": "sqlite",
|
||||
"provider": "rag",
|
||||
"use_embedding": True,
|
||||
"storage": {
|
||||
"type": "sqlite",
|
||||
@@ -105,13 +105,13 @@ def main():
|
||||
agents=[researcher, retriever],
|
||||
tasks=[store_task, verify_task, query_task, query_both_task], # Use same verbose level as memory
|
||||
memory={
|
||||
"provider": "rag",
|
||||
"embedder": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "text-embedding-3-small"
|
||||
}
|
||||
},
|
||||
"config": {"provider": "sqlite"},
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -49,20 +49,10 @@ agents = AgentTeam(
|
||||
process="sequential"
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run all tasks
|
||||
result = agents.start()
|
||||
# Run all tasks
|
||||
result = agents.start()
|
||||
|
||||
# Print results
|
||||
task_results = result.get("task_results") if isinstance(result, dict) else result
|
||||
if isinstance(task_results, dict):
|
||||
iterable = task_results.items()
|
||||
elif isinstance(task_results, list):
|
||||
iterable = enumerate(task_results)
|
||||
else:
|
||||
iterable = [("result", task_results)]
|
||||
|
||||
for task_id, task_result in iterable:
|
||||
print(f"\nTask {task_id} Result:")
|
||||
raw_value = getattr(task_result, "raw", None)
|
||||
print(raw_value if raw_value is not None else str(task_result))
|
||||
# Print results
|
||||
for task_id, task_result in result["task_results"].items():
|
||||
print(f"\nTask {task_id} Result:")
|
||||
print(task_result.raw)
|
||||
@@ -6,7 +6,6 @@ built-in validation and safety mechanisms for secure agent operations.
|
||||
"""
|
||||
|
||||
from praisonaiagents import Agent, Task, AgentTeam
|
||||
from praisonaiagents.config.feature_configs import GuardrailConfig
|
||||
from praisonaiagents.tools import internet_search
|
||||
|
||||
print("=== Production Guardrails Patterns Example ===\n")
|
||||
@@ -39,8 +38,8 @@ production_agent = Agent(
|
||||
goal="Generate safe, compliant content for production use",
|
||||
backstory="Production-ready agent with built-in safety and compliance checks",
|
||||
tools=[internet_search],
|
||||
guardrails=GuardrailConfig(validator=content_guardrail, max_retries=3),
|
||||
)
|
||||
guardrails=content_guardrail,
|
||||
max_retries=3)
|
||||
|
||||
# Create secure task with validation
|
||||
secure_task = Task(
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
"""
|
||||
Linear Agent Example for PraisonAI.
|
||||
|
||||
Demonstrates how to create a Linear bot that responds to issue mentions
|
||||
and assignments with full coding capabilities.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from praisonaiagents import Agent
|
||||
from praisonai.bots import LinearBot
|
||||
|
||||
# Create an agent with Linear tools and coding capabilities
|
||||
agent = Agent(
|
||||
name="PraisonAI Coder",
|
||||
instructions="""
|
||||
You are an autonomous coding agent integrated with Linear.
|
||||
|
||||
When you are mentioned or assigned an issue:
|
||||
1. Analyze the issue description and requirements
|
||||
2. Break down complex tasks into smaller steps
|
||||
3. Use available tools to implement solutions
|
||||
4. Update the issue with progress comments
|
||||
5. Create GitHub pull requests when code changes are needed
|
||||
|
||||
Focus on being helpful, thorough, and providing clear updates.
|
||||
""",
|
||||
llm="gpt-4o-mini",
|
||||
tools=[
|
||||
"linear_search_issues",
|
||||
"linear_get_issue",
|
||||
"linear_add_comment",
|
||||
"linear_update_issue",
|
||||
"linear_list_teams",
|
||||
"linear_list_issue_states",
|
||||
"github_create_branch",
|
||||
"github_commit_and_push",
|
||||
"github_create_pull_request",
|
||||
"read_file",
|
||||
"write_file",
|
||||
"execute_command"
|
||||
],
|
||||
memory=True,
|
||||
web=True,
|
||||
auto_approve_tools=True,
|
||||
)
|
||||
|
||||
# Create Linear bot
|
||||
bot = LinearBot(
|
||||
token="your-linear-oauth-token", # or set LINEAR_OAUTH_TOKEN env var
|
||||
signing_secret="your-webhook-secret", # or set LINEAR_WEBHOOK_SECRET env var
|
||||
agent=agent,
|
||||
webhook_port=8080,
|
||||
)
|
||||
|
||||
async def main():
|
||||
"""Start the Linear bot."""
|
||||
print("Starting Linear bot...")
|
||||
print("Set up your Linear webhook to point to: http://your-host:8080/webhook")
|
||||
print("Configure AgentSession and Comment events in Linear webhook settings")
|
||||
|
||||
try:
|
||||
await bot.start()
|
||||
except KeyboardInterrupt:
|
||||
print("\nStopping bot...")
|
||||
await bot.stop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -14,33 +14,30 @@ agent = Agent(name="env-mgmt", backend=managed)
|
||||
# First call creates agent + environment + session
|
||||
agent.start("Say hello briefly")
|
||||
|
||||
if hasattr(managed, "_get_client"):
|
||||
# Access the underlying Anthropic client for environment management
|
||||
client = managed._get_client()
|
||||
env_id = managed.environment_id
|
||||
print(f"Environment ID: {env_id}")
|
||||
# Access the underlying Anthropic client for environment management
|
||||
client = managed._get_client()
|
||||
env_id = managed.environment_id
|
||||
print(f"Environment ID: {env_id}")
|
||||
|
||||
# List all environments
|
||||
environments = client.beta.environments.list()
|
||||
print(f"\nTotal environments: {len(environments.data)}")
|
||||
for env in environments.data[:5]:
|
||||
print(f" {env.id} | {env.name} | {getattr(env, 'status', 'active')}")
|
||||
# List all environments
|
||||
environments = client.beta.environments.list()
|
||||
print(f"\nTotal environments: {len(environments.data)}")
|
||||
for env in environments.data[:5]:
|
||||
print(f" {env.id} | {env.name} | {getattr(env, 'status', 'active')}")
|
||||
|
||||
# Retrieve a specific environment
|
||||
env = client.beta.environments.retrieve(env_id)
|
||||
print(f"\nRetrieved: {env.id} | {env.name}")
|
||||
# Retrieve a specific environment
|
||||
env = client.beta.environments.retrieve(env_id)
|
||||
print(f"\nRetrieved: {env.id} | {env.name}")
|
||||
|
||||
# Archive (read-only, existing sessions continue)
|
||||
archived = client.beta.environments.archive(env_id)
|
||||
print(f"Archived: {archived.id} | status: {getattr(archived, 'status', 'archived')}")
|
||||
# Archive (read-only, existing sessions continue)
|
||||
archived = client.beta.environments.archive(env_id)
|
||||
print(f"Archived: {archived.id} | status: {getattr(archived, 'status', 'archived')}")
|
||||
|
||||
# Delete (only if no sessions reference it — may fail if sessions exist)
|
||||
try:
|
||||
client.beta.environments.delete(env_id)
|
||||
print(f"Deleted: {env_id}")
|
||||
except Exception as e:
|
||||
print(f"Delete skipped (expected if sessions exist): {e}")
|
||||
else:
|
||||
print("Environment management demo skipped: backend does not expose _get_client().")
|
||||
# Delete (only if no sessions reference it — may fail if sessions exist)
|
||||
try:
|
||||
client.beta.environments.delete(env_id)
|
||||
print(f"Deleted: {env_id}")
|
||||
except Exception as e:
|
||||
print(f"Delete skipped (expected if sessions exist): {e}")
|
||||
|
||||
print("\nEnvironment management complete.")
|
||||
@@ -1,7 +1,7 @@
|
||||
"""All compute providers — comprehensive test across Local, Docker, E2B, and Modal.
|
||||
|
||||
This example demonstrates local agent loops with various compute backends for tool sandboxing.
|
||||
Uses the new LocalAgent class to clearly indicate local execution with optional cloud compute.
|
||||
This example mirrors the Anthropic app.py but uses the local provider with
|
||||
various compute backends instead of Anthropic's managed infrastructure.
|
||||
|
||||
Requires:
|
||||
- Docker running locally
|
||||
@@ -9,8 +9,7 @@ Requires:
|
||||
- modal CLI configured (modal token set)
|
||||
"""
|
||||
import asyncio
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import LocalAgent, LocalAgentConfig
|
||||
from praisonai import Agent, ManagedAgent, LocalManagedConfig
|
||||
|
||||
|
||||
async def test_provider(name, compute, extra_provision_kwargs=None):
|
||||
@@ -19,9 +18,10 @@ async def test_provider(name, compute, extra_provision_kwargs=None):
|
||||
print(f" PROVIDER: {name}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
managed = LocalAgent(
|
||||
managed = ManagedAgent(
|
||||
provider="local",
|
||||
compute=compute,
|
||||
config=LocalAgentConfig(
|
||||
config=LocalManagedConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a helpful assistant. Be concise.",
|
||||
name=f"{name}Agent",
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
"""Run every managed-runtime example and report a summary.
|
||||
|
||||
Executes the runtime_*.py files in this directory as subprocesses with a
|
||||
30s per-example timeout. Exits non-zero if any example fails.
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
EXAMPLES = [
|
||||
# ── LLM providers (where the LLM reasoning happens) ──
|
||||
"runtime_anthropic.py", # full loop in Anthropic cloud
|
||||
"runtime_openai.py", # LLM in OpenAI cloud
|
||||
"runtime_gemini.py", # LLM in Google cloud
|
||||
"runtime_ollama.py", # LLM on local/self-hosted Ollama
|
||||
# ── Cloud/compute providers (where tool execution happens) ──
|
||||
"runtime_e2b.py", # tools sandboxed in E2B cloud VM
|
||||
"runtime_modal.py", # tools sandboxed in Modal serverless cloud
|
||||
"runtime_fly.py", # tools sandboxed on Fly.io Machines
|
||||
"runtime_daytona.py", # tools sandboxed in Daytona cloud workspace
|
||||
"runtime_docker.py", # tools sandboxed in local Docker container
|
||||
]
|
||||
|
||||
results = []
|
||||
for name in EXAMPLES:
|
||||
path = os.path.join(HERE, name)
|
||||
start = time.time()
|
||||
proc = subprocess.run(
|
||||
[sys.executable, path],
|
||||
capture_output=True, text=True, timeout=120,
|
||||
env=os.environ.copy(), # propagate API keys and PYTHONPATH
|
||||
)
|
||||
dur = time.time() - start
|
||||
ok = proc.returncode == 0
|
||||
results.append((name, ok, dur, proc.stdout.strip().splitlines()[-1] if proc.stdout.strip() else ""))
|
||||
print(f"[{'OK' if ok else 'FAIL'}] {name:30s} {dur:.2f}s")
|
||||
if not ok:
|
||||
print(proc.stdout)
|
||||
print(proc.stderr)
|
||||
|
||||
print("\nSummary:")
|
||||
for name, ok, dur, tail in results:
|
||||
print(f" {'✓' if ok else '✗'} {name:30s} {dur:5.2f}s {tail[:60]}")
|
||||
|
||||
sys.exit(0 if all(r[1] for r in results) else 1)
|
||||
@@ -23,39 +23,12 @@ print(f"[2] Updated to v{managed.agent_version}")
|
||||
result = agent.start("What is 123 + 456?", stream=True)
|
||||
|
||||
# ── 3. Custom tool ──
|
||||
def _safe_calc(expr: str) -> str:
|
||||
import ast
|
||||
allowed = set("0123456789+-*/.() ")
|
||||
if not all(c in allowed for c in expr):
|
||||
return "error"
|
||||
try:
|
||||
tree = ast.parse(expr, mode="eval")
|
||||
for node in ast.walk(tree):
|
||||
if not isinstance(
|
||||
node,
|
||||
(
|
||||
ast.Expression,
|
||||
ast.BinOp,
|
||||
ast.UnaryOp,
|
||||
ast.Constant,
|
||||
ast.Add,
|
||||
ast.Sub,
|
||||
ast.Mult,
|
||||
ast.Div,
|
||||
ast.USub,
|
||||
ast.UAdd,
|
||||
),
|
||||
):
|
||||
return "error"
|
||||
val = eval(compile(tree, "<expr>", "eval"), {"__builtins__": {}})
|
||||
return str(val)
|
||||
except Exception:
|
||||
return "error"
|
||||
|
||||
|
||||
def handle_calculator(tool_name, tool_input):
|
||||
expr = tool_input.get("expression", "0")
|
||||
val = _safe_calc(str(expr))
|
||||
try:
|
||||
val = eval(expr, {"__builtins__": {}})
|
||||
except Exception:
|
||||
val = "error"
|
||||
print(f" [Calculator: {expr} = {val}]")
|
||||
return str(val)
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
"""Local agent — basic local execution with gpt-4o-mini.
|
||||
"""Local provider — basic managed agent with gpt-4o-mini.
|
||||
|
||||
No external infrastructure needed. Runs the agent loop locally.
|
||||
Uses the new canonical LocalAgent class for clarity.
|
||||
"""
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import LocalAgent, LocalAgentConfig
|
||||
from praisonai import Agent, ManagedAgent, LocalManagedConfig
|
||||
|
||||
# Create a local agent (runs locally, no managed runtime)
|
||||
managed = LocalAgent(
|
||||
config=LocalAgentConfig(
|
||||
# Create a local managed agent (auto-detects local when no ANTHROPIC_API_KEY)
|
||||
managed = ManagedAgent(
|
||||
provider="local",
|
||||
config=LocalManagedConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a helpful assistant. Be concise.",
|
||||
name="LocalAgent",
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
"""Anthropic managed runtime — full agent loop runs in Anthropic's cloud.
|
||||
|
||||
The ENTIRE loop (LLM calls, tool execution, memory, sessions) runs remotely
|
||||
on Anthropic's managed infrastructure. This is the only provider today where
|
||||
"the whole thing runs in that cloud".
|
||||
|
||||
Requires: ANTHROPIC_API_KEY environment variable set.
|
||||
"""
|
||||
import os
|
||||
|
||||
if not os.getenv("ANTHROPIC_API_KEY"):
|
||||
print("[skip] ANTHROPIC_API_KEY not set — set it to run this example.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
import anthropic # noqa: F401 (required by AnthropicManagedAgent)
|
||||
except ImportError:
|
||||
print("[skip] 'anthropic' SDK not installed — pip install 'anthropic>=0.94.0'")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
try:
|
||||
from praisonai import Agent, ManagedAgent, ManagedConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
managed = ManagedAgent(
|
||||
provider="anthropic",
|
||||
config=ManagedConfig(
|
||||
model="claude-3-5-sonnet-latest",
|
||||
system="You are a concise coding assistant. One-sentence answers.",
|
||||
name="AnthropicRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="anthropic-runtime", backend=managed)
|
||||
|
||||
# 1. Agent work entirely in the cloud
|
||||
print("[1] Agent:", agent.start("Write a Python one-liner that sums 1..10. Just the code."))
|
||||
|
||||
# 2. Multi-turn reuses the same cloud session
|
||||
print("[2] Agent:", agent.start("Now change it to factorial of 5."))
|
||||
|
||||
# 3. Cloud-side session metadata
|
||||
info = managed.retrieve_session()
|
||||
print(f"[3] session={managed.session_id} status={info.get('status')} "
|
||||
f"in={info.get('usage', {}).get('input_tokens', 0)} "
|
||||
f"out={info.get('usage', {}).get('output_tokens', 0)}")
|
||||
@@ -1,52 +0,0 @@
|
||||
"""Agent runtime with tools sandboxed in a Daytona cloud workspace.
|
||||
|
||||
The agent's LLM loop runs locally; tool / code execution runs in a Daytona-
|
||||
managed workspace (disposable cloud dev environment, pre-configured images).
|
||||
|
||||
Requires:
|
||||
- ``OPENAI_API_KEY`` for the LLM
|
||||
- ``DAYTONA_API_KEY`` for the Daytona API
|
||||
- ``pip install daytona-sdk``
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set.")
|
||||
raise SystemExit(0)
|
||||
if not os.getenv("DAYTONA_API_KEY"):
|
||||
print("[skip] DAYTONA_API_KEY not set.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import SandboxedAgent, SandboxedAgentConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
|
||||
async def main():
|
||||
sandboxed = SandboxedAgent(
|
||||
compute="daytona", # tool execution runs in a Daytona workspace
|
||||
config=SandboxedAgentConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a concise coding assistant.",
|
||||
name="DaytonaRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="daytona-runtime", backend=sandboxed)
|
||||
|
||||
info = await sandboxed.provision_compute(idle_timeout_s=120)
|
||||
print(f"[1] Daytona workspace: {info.instance_id} ({info.status})")
|
||||
|
||||
result = await sandboxed.execute_in_compute("python3 -c 'print(len([1,2,3,4,5]) ** 3)'")
|
||||
print(f"[2] Cloud compute result: {result['stdout'].strip()}")
|
||||
|
||||
print("[3] Agent:", agent.start("What is 5 cubed? Just the number."))
|
||||
|
||||
await sandboxed.shutdown_compute()
|
||||
print("[4] Daytona workspace shut down.")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,59 +0,0 @@
|
||||
"""Agent runtime with tools sandboxed in a local Docker container.
|
||||
|
||||
The agent's LLM loop runs locally; tool / code execution is isolated in a
|
||||
Docker container. Not a cloud provider, but the same pattern — useful for
|
||||
local development and CI.
|
||||
|
||||
Requires:
|
||||
- ``OPENAI_API_KEY`` for the LLM
|
||||
- Docker daemon running (``docker info`` must succeed)
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
subprocess.run(
|
||||
["docker", "info"],
|
||||
check=True, capture_output=True, timeout=5,
|
||||
)
|
||||
except (subprocess.CalledProcessError, subprocess.TimeoutExpired, FileNotFoundError):
|
||||
print("[skip] Docker daemon not available — start Docker Desktop.")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
try:
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import SandboxedAgent, SandboxedAgentConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
|
||||
async def main():
|
||||
sandboxed = SandboxedAgent(
|
||||
compute="docker", # tool execution runs in a local Docker container
|
||||
config=SandboxedAgentConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a concise coding assistant.",
|
||||
name="DockerRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="docker-runtime", backend=sandboxed)
|
||||
|
||||
info = await sandboxed.provision_compute(image="python:3.12-slim")
|
||||
print(f"[1] Docker container: {info.instance_id} ({info.status})")
|
||||
|
||||
result = await sandboxed.execute_in_compute("python3 -c 'print(sum(i*i for i in range(1, 11)))'")
|
||||
print(f"[2] Container compute result: {result['stdout'].strip()}")
|
||||
|
||||
print("[3] Agent:", agent.start("What is the sum of squares from 1 to 10? Just the number."))
|
||||
|
||||
await sandboxed.shutdown_compute()
|
||||
print("[4] Docker container shut down.")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,56 +0,0 @@
|
||||
"""Agent runtime with tools sandboxed in an E2B cloud VM.
|
||||
|
||||
The agent's LLM loop runs locally; any tool / code execution is sandboxed
|
||||
in an ephemeral E2B cloud instance. Uses ``SandboxedAgent`` — the honest
|
||||
name for the "local loop + cloud tools" pattern.
|
||||
|
||||
Requires:
|
||||
- ``OPENAI_API_KEY`` for the LLM
|
||||
- ``E2B_API_KEY`` for the cloud sandbox
|
||||
- ``pip install e2b``
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set.")
|
||||
raise SystemExit(0)
|
||||
if not os.getenv("E2B_API_KEY"):
|
||||
print("[skip] E2B_API_KEY not set — set it to run in the E2B cloud sandbox.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import SandboxedAgent, SandboxedAgentConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
|
||||
async def main():
|
||||
sandboxed = SandboxedAgent(
|
||||
compute="e2b", # tool execution runs in E2B cloud
|
||||
config=SandboxedAgentConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a concise coding assistant.",
|
||||
name="E2BRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="e2b-runtime", backend=sandboxed)
|
||||
|
||||
# 1. Provision the cloud sandbox
|
||||
info = await sandboxed.provision_compute(idle_timeout_s=120)
|
||||
print(f"[1] E2B sandbox: {info.instance_id} ({info.status})")
|
||||
|
||||
# 2. Execute code IN the cloud sandbox
|
||||
result = await sandboxed.execute_in_compute("python3 -c 'print(sum(range(1, 11)))'")
|
||||
print(f"[2] Cloud compute result: {result['stdout'].strip()}")
|
||||
|
||||
# 3. Agent loop (LLM local, any tool calls auto-sandboxed in E2B)
|
||||
print("[3] Agent:", agent.start("What is 13 * 17? Just the number."))
|
||||
|
||||
await sandboxed.shutdown_compute()
|
||||
print("[4] E2B sandbox shut down.")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,57 +0,0 @@
|
||||
"""Agent runtime with tools sandboxed on Fly.io Machines.
|
||||
|
||||
The agent's LLM loop runs locally; tool / code execution runs in a Fly.io
|
||||
Machine (fast-booting micro-VM with per-second billing and global regions).
|
||||
|
||||
Requires:
|
||||
- ``OPENAI_API_KEY`` for the LLM
|
||||
- ``FLY_API_TOKEN`` for the Fly.io Machines API
|
||||
- ``FLY_APP_NAME`` (optional) existing Fly app; auto-created otherwise
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set.")
|
||||
raise SystemExit(0)
|
||||
if not os.getenv("FLY_API_TOKEN"):
|
||||
print("[skip] FLY_API_TOKEN not set — get one via `fly auth token`.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import SandboxedAgent, SandboxedAgentConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
|
||||
async def main():
|
||||
sandboxed = SandboxedAgent(
|
||||
compute="flyio", # tool execution runs on Fly.io Machines
|
||||
config=SandboxedAgentConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a concise coding assistant.",
|
||||
name="FlyioRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="fly-runtime", backend=sandboxed)
|
||||
|
||||
info = await sandboxed.provision_compute(
|
||||
image="python:3.12-slim",
|
||||
cpu=1,
|
||||
memory_mb=512,
|
||||
idle_timeout_s=120,
|
||||
)
|
||||
print(f"[1] Fly Machine: {info.instance_id} ({info.status})")
|
||||
|
||||
result = await sandboxed.execute_in_compute("python3 -c 'print(2 ** 20)'")
|
||||
print(f"[2] Cloud compute result: {result['stdout'].strip()}")
|
||||
|
||||
print("[3] Agent:", agent.start("What is 2 raised to the 20th power? Just the number."))
|
||||
|
||||
await sandboxed.shutdown_compute()
|
||||
print("[4] Fly Machine shut down.")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,40 +0,0 @@
|
||||
"""Gemini managed runtime — agent loop local, LLM calls go to Google's cloud.
|
||||
|
||||
``ManagedAgent(provider="gemini")`` wires a local managed loop to Gemini's
|
||||
hosted models via litellm.
|
||||
|
||||
Requires: GEMINI_API_KEY (or GOOGLE_API_KEY) environment variable set.
|
||||
"""
|
||||
import os
|
||||
|
||||
if not (os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")):
|
||||
print("[skip] GEMINI_API_KEY / GOOGLE_API_KEY not set — set one to run this example.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent, ManagedAgent, LocalManagedConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
managed = ManagedAgent(
|
||||
provider="gemini",
|
||||
config=LocalManagedConfig(
|
||||
# Use explicit litellm prefix to guarantee routing to Google
|
||||
model="gemini/gemini-2.0-flash-exp",
|
||||
system="You are a concise assistant. One-sentence answers.",
|
||||
name="GeminiRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="gemini-runtime", backend=managed)
|
||||
|
||||
# 1. Agent work (LLM call goes to Google cloud)
|
||||
print("[1] Agent:", agent.start("What does REST stand for? One sentence."))
|
||||
|
||||
# 2. Multi-turn reuses the session
|
||||
print("[2] Agent:", agent.start("How is it different from GraphQL?"))
|
||||
|
||||
info = managed.retrieve_session()
|
||||
print(f"[3] session={managed.session_id} "
|
||||
f"in={info.get('usage', {}).get('input_tokens', 0)} "
|
||||
f"out={info.get('usage', {}).get('output_tokens', 0)}")
|
||||
@@ -1,63 +0,0 @@
|
||||
"""Anthropic hosted runtime — entire agent runs on Anthropic's managed infrastructure.
|
||||
|
||||
Uses the new canonical HostedAgent class which clearly communicates that the entire
|
||||
agent loop runs in Anthropic's cloud, not locally.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Skip guards - exit cleanly if prerequisites not met
|
||||
if not (os.getenv("ANTHROPIC_API_KEY") or os.getenv("CLAUDE_API_KEY")):
|
||||
print("[skip] ANTHROPIC_API_KEY or CLAUDE_API_KEY not set")
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
import anthropic
|
||||
except ImportError:
|
||||
print("[skip] anthropic SDK not installed")
|
||||
sys.exit(0)
|
||||
|
||||
# Heavy imports only after skip-guards pass
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import HostedAgent, HostedAgentConfig
|
||||
|
||||
# Create a hosted agent running entirely on Anthropic's managed runtime
|
||||
hosted = HostedAgent(
|
||||
provider="anthropic",
|
||||
config=HostedAgentConfig(
|
||||
model="claude-3-5-sonnet-latest",
|
||||
system="You are a helpful coding assistant. Be concise.",
|
||||
name="AnthropicHostedAgent",
|
||||
tools=[{"type": "agent_toolset_20260401"}],
|
||||
),
|
||||
)
|
||||
|
||||
agent = Agent(name="anthropic-hosted", backend=hosted)
|
||||
|
||||
# 1. Basic execution - runs entirely in Anthropic's cloud
|
||||
print("[1] Hosted execution on Anthropic infrastructure...")
|
||||
result = agent.start("What is the capital of France? One word.", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 2. Agent metadata from Anthropic's API
|
||||
print(f"\n[2] Agent ID: {hosted.agent_id}")
|
||||
print(f" Version: {hosted.agent_version}")
|
||||
print(f" Env ID: {hosted.environment_id}")
|
||||
print(f" Session: {hosted.session_id}")
|
||||
|
||||
# 3. Multi-turn (same session keeps context in Anthropic's cloud)
|
||||
print("\n[3] Multi-turn conversation...")
|
||||
result = agent.start("What country is that city in?", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 4. Usage tracking from Anthropic's usage API
|
||||
info = hosted.retrieve_session()
|
||||
print(f"\n[4] Usage: in={info['usage']['input_tokens']}, out={info['usage']['output_tokens']}")
|
||||
|
||||
# 5. List all sessions for this agent
|
||||
sessions = hosted.list_sessions()
|
||||
print(f"\n[5] Sessions: {len(sessions)}")
|
||||
for s in sessions[:3]: # Show first 3
|
||||
print(f" {s['id']} | {s['status']}")
|
||||
|
||||
print("\nDone! Agent loop ran entirely on Anthropic's managed infrastructure.")
|
||||
@@ -1,61 +0,0 @@
|
||||
"""Local agent loop with Gemini LLM — runs locally, not in a managed runtime.
|
||||
|
||||
Uses the new canonical LocalAgent class which clearly communicates that only the
|
||||
agent loop runs locally. The LLM calls go to Google's Gemini API, but there's no managed runtime involved.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Skip guards - exit cleanly if prerequisites not met
|
||||
if not (os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")):
|
||||
print("[skip] GEMINI_API_KEY or GOOGLE_API_KEY not set")
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
import google.generativeai
|
||||
except ImportError:
|
||||
print("[skip] google-generativeai SDK not installed")
|
||||
sys.exit(0)
|
||||
|
||||
# Heavy imports only after skip-guards pass
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import LocalAgent, LocalAgentConfig
|
||||
|
||||
# Create a local agent using Gemini LLM
|
||||
local = LocalAgent(
|
||||
config=LocalAgentConfig(
|
||||
model="gemini/gemini-2.0-flash", # Use Gemini with litellm routing prefix
|
||||
system="You are a helpful coding assistant. Be concise.",
|
||||
name="LocalGeminiAgent",
|
||||
tools=["execute_command", "read_file", "write_file"],
|
||||
),
|
||||
)
|
||||
|
||||
agent = Agent(name="local-gemini", backend=local)
|
||||
|
||||
# 1. Basic execution - agent loop runs locally, LLM calls go to Gemini
|
||||
print("[1] Local execution with Gemini LLM...")
|
||||
result = agent.start("What is the capital of France? One word.", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 2. Agent metadata (locally generated UUIDs)
|
||||
print(f"\n[2] Agent ID: {local.agent_id}")
|
||||
print(f" Version: {local.agent_version}")
|
||||
print(f" Env ID: {local.environment_id}")
|
||||
print(f" Session: {local.session_id}")
|
||||
|
||||
# 3. Multi-turn conversation (session state maintained locally)
|
||||
print("\n[3] Multi-turn conversation...")
|
||||
result = agent.start("What country is that city in?", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 4. Usage tracking (accumulated locally)
|
||||
info = local.retrieve_session()
|
||||
print(f"\n[4] Usage: in={info['usage']['input_tokens']}, out={info['usage']['output_tokens']}")
|
||||
|
||||
# 5. Tool execution (runs in local subprocess)
|
||||
print("\n[5] Tool execution example...")
|
||||
result = agent.start("Create a file called hello_gemini.txt with 'Hello from Gemini agent!'", stream=True)
|
||||
print(f" Tool result: {result}")
|
||||
|
||||
print("\nDone! Agent loop ran locally with Gemini LLM calls.")
|
||||
@@ -1,61 +0,0 @@
|
||||
"""Local agent loop with Ollama LLM — runs locally, not in a managed runtime.
|
||||
|
||||
Uses the new canonical LocalAgent class which clearly communicates that only the
|
||||
agent loop runs locally. The LLM calls go to a local Ollama instance, no managed runtime involved.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
|
||||
# Skip guards - exit cleanly if prerequisites not met
|
||||
# Check if Ollama daemon is running
|
||||
try:
|
||||
response = requests.get("http://localhost:11434/api/tags", timeout=2)
|
||||
if response.status_code != 200:
|
||||
raise Exception("Ollama not responding")
|
||||
except Exception:
|
||||
print("[skip] Ollama daemon not running at localhost:11434")
|
||||
sys.exit(0)
|
||||
|
||||
# Heavy imports only after skip-guards pass
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import LocalAgent, LocalAgentConfig
|
||||
|
||||
# Create a local agent using Ollama LLM
|
||||
local = LocalAgent(
|
||||
config=LocalAgentConfig(
|
||||
model="ollama/llama3.2", # Use Ollama with litellm routing prefix
|
||||
system="You are a helpful coding assistant. Be concise.",
|
||||
name="LocalOllamaAgent",
|
||||
tools=["execute_command", "read_file", "write_file"],
|
||||
),
|
||||
)
|
||||
|
||||
agent = Agent(name="local-ollama", backend=local)
|
||||
|
||||
# 1. Basic execution - agent loop runs locally, LLM calls go to local Ollama
|
||||
print("[1] Local execution with Ollama LLM...")
|
||||
result = agent.start("What is the capital of France? One word.", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 2. Agent metadata (locally generated UUIDs)
|
||||
print(f"\n[2] Agent ID: {local.agent_id}")
|
||||
print(f" Version: {local.agent_version}")
|
||||
print(f" Env ID: {local.environment_id}")
|
||||
print(f" Session: {local.session_id}")
|
||||
|
||||
# 3. Multi-turn conversation (session state maintained locally)
|
||||
print("\n[3] Multi-turn conversation...")
|
||||
result = agent.start("What country is that city in?", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 4. Usage tracking (accumulated locally)
|
||||
info = local.retrieve_session()
|
||||
print(f"\n[4] Usage: in={info['usage']['input_tokens']}, out={info['usage']['output_tokens']}")
|
||||
|
||||
# 5. Tool execution (runs in local subprocess)
|
||||
print("\n[5] Tool execution example...")
|
||||
result = agent.start("Create a file called hello_ollama.txt with 'Hello from Ollama agent!'", stream=True)
|
||||
print(f" Tool result: {result}")
|
||||
|
||||
print("\nDone! Agent loop ran locally with Ollama LLM calls.")
|
||||
@@ -1,61 +0,0 @@
|
||||
"""Local agent loop with OpenAI LLM — runs locally, not in a managed runtime.
|
||||
|
||||
Uses the new canonical LocalAgent class which clearly communicates that only the
|
||||
agent loop runs locally. The LLM calls go to OpenAI, but there's no managed runtime involved.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Skip guards - exit cleanly if prerequisites not met
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set")
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
import openai
|
||||
except ImportError:
|
||||
print("[skip] openai SDK not installed")
|
||||
sys.exit(0)
|
||||
|
||||
# Heavy imports only after skip-guards pass
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import LocalAgent, LocalAgentConfig
|
||||
|
||||
# Create a local agent using OpenAI's LLM
|
||||
local = LocalAgent(
|
||||
config=LocalAgentConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a helpful coding assistant. Be concise.",
|
||||
name="LocalOpenAIAgent",
|
||||
tools=["execute_command", "read_file", "write_file"],
|
||||
),
|
||||
)
|
||||
|
||||
agent = Agent(name="local-openai", backend=local)
|
||||
|
||||
# 1. Basic execution - agent loop runs locally, LLM calls go to OpenAI
|
||||
print("[1] Local execution with OpenAI LLM...")
|
||||
result = agent.start("What is the capital of France? One word.", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 2. Agent metadata (locally generated UUIDs)
|
||||
print(f"\n[2] Agent ID: {local.agent_id}")
|
||||
print(f" Version: {local.agent_version}")
|
||||
print(f" Env ID: {local.environment_id}")
|
||||
print(f" Session: {local.session_id}")
|
||||
|
||||
# 3. Multi-turn conversation (session state maintained locally)
|
||||
print("\n[3] Multi-turn conversation...")
|
||||
result = agent.start("What country is that city in?", stream=True)
|
||||
print(f" Result: {result}")
|
||||
|
||||
# 4. Usage tracking (accumulated locally)
|
||||
info = local.retrieve_session()
|
||||
print(f"\n[4] Usage: in={info['usage']['input_tokens']}, out={info['usage']['output_tokens']}")
|
||||
|
||||
# 5. Tool execution (runs in local subprocess)
|
||||
print("\n[5] Tool execution example...")
|
||||
result = agent.start("Create a file called hello.txt with 'Hello from local agent!'", stream=True)
|
||||
print(f" Tool result: {result}")
|
||||
|
||||
print("\nDone! Agent loop ran locally with OpenAI LLM calls.")
|
||||
@@ -1,61 +0,0 @@
|
||||
"""Agent runtime with tools sandboxed in Modal cloud functions.
|
||||
|
||||
The agent's LLM loop runs locally; tool / code execution is sandboxed in
|
||||
Modal's serverless cloud. Modal gives fast cold-starts and per-second billing.
|
||||
|
||||
Requires:
|
||||
- ``OPENAI_API_KEY`` for the LLM
|
||||
- Modal CLI configured: ``modal token set --token-id ... --token-secret ...``
|
||||
- ``pip install modal``
|
||||
"""
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
import modal # noqa: F401
|
||||
except ImportError:
|
||||
print("[skip] 'modal' package not installed — pip install modal")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
# Modal auth: presence of ~/.modal.toml or MODAL_TOKEN_ID + MODAL_TOKEN_SECRET
|
||||
if not (os.path.exists(os.path.expanduser("~/.modal.toml"))
|
||||
or (os.getenv("MODAL_TOKEN_ID") and os.getenv("MODAL_TOKEN_SECRET"))):
|
||||
print("[skip] Modal not configured — run `modal token set ...`")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent
|
||||
from praisonai.integrations import SandboxedAgent, SandboxedAgentConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
|
||||
async def main():
|
||||
sandboxed = SandboxedAgent(
|
||||
compute="modal", # tool execution runs in Modal's cloud
|
||||
config=SandboxedAgentConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a concise coding assistant.",
|
||||
name="ModalRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="modal-runtime", backend=sandboxed)
|
||||
|
||||
info = await sandboxed.provision_compute(idle_timeout_s=120)
|
||||
print(f"[1] Modal instance: {info.instance_id} ({info.status})")
|
||||
|
||||
result = await sandboxed.execute_in_compute("python3 -c 'import math; print(math.factorial(10))'")
|
||||
print(f"[2] Cloud compute result: {result['stdout'].strip()}")
|
||||
|
||||
print("[3] Agent:", agent.start("What is the 10th Fibonacci number? Just the number."))
|
||||
|
||||
await sandboxed.shutdown_compute()
|
||||
print("[4] Modal instance shut down.")
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,45 +0,0 @@
|
||||
"""Ollama managed runtime — agent runs against a local/self-hosted LLM.
|
||||
|
||||
``ManagedAgent(provider="ollama")`` wires the managed loop to an Ollama
|
||||
server. Model runs locally (or on a self-hosted box) instead of in a public
|
||||
cloud — useful when you want the "managed agent" developer experience with
|
||||
no external API dependency.
|
||||
|
||||
Requires: An Ollama server reachable (default ``http://localhost:11434``)
|
||||
with at least one model pulled (e.g., ``ollama pull llama3.2``).
|
||||
"""
|
||||
import os
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
base = os.getenv("OLLAMA_HOST", "http://localhost:11434")
|
||||
try:
|
||||
urllib.request.urlopen(f"{base}/api/tags", timeout=2).read()
|
||||
except (urllib.error.URLError, OSError) as e:
|
||||
print(f"[skip] Ollama not reachable at {base} ({e}). Start it with `ollama serve`.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent, ManagedAgent, LocalManagedConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
managed = ManagedAgent(
|
||||
provider="ollama",
|
||||
config=LocalManagedConfig(
|
||||
model="llama3.2",
|
||||
system="You are a concise assistant. One-sentence answers.",
|
||||
name="OllamaRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="ollama-runtime", backend=managed)
|
||||
|
||||
# 1. Agent work (LLM call goes to your Ollama server)
|
||||
print("[1] Agent:", agent.start("What is the capital of Japan? One word."))
|
||||
|
||||
# 2. Multi-turn reuses the session
|
||||
print("[2] Agent:", agent.start("Name its most famous mountain."))
|
||||
|
||||
info = managed.retrieve_session()
|
||||
print(f"[3] session={managed.session_id}")
|
||||
@@ -1,41 +0,0 @@
|
||||
"""OpenAI managed runtime — agent loop local, LLM calls go to OpenAI cloud.
|
||||
|
||||
``ManagedAgent(provider="openai")`` wires a local managed loop to OpenAI's
|
||||
hosted models. The LLM reasoning (the heavy-lifting) runs in OpenAI's cloud;
|
||||
the agent orchestration (tool routing, session state) runs in this process.
|
||||
|
||||
Requires: OPENAI_API_KEY environment variable set.
|
||||
"""
|
||||
import os
|
||||
|
||||
if not os.getenv("OPENAI_API_KEY"):
|
||||
print("[skip] OPENAI_API_KEY not set — set it to run this example.")
|
||||
raise SystemExit(0)
|
||||
|
||||
try:
|
||||
from praisonai import Agent, ManagedAgent, LocalManagedConfig
|
||||
except ImportError as e:
|
||||
print(f"[skip] praisonai wrapper not importable ({e}).")
|
||||
raise SystemExit(0) from None
|
||||
|
||||
managed = ManagedAgent(
|
||||
provider="openai",
|
||||
config=LocalManagedConfig(
|
||||
model="gpt-4o-mini",
|
||||
system="You are a concise assistant. One-sentence answers.",
|
||||
name="OpenAIRuntimeAgent",
|
||||
),
|
||||
)
|
||||
agent = Agent(name="openai-runtime", backend=managed)
|
||||
|
||||
# 1. Agent work (LLM call goes to OpenAI cloud)
|
||||
print("[1] Agent:", agent.start("What is the time complexity of binary search? One sentence."))
|
||||
|
||||
# 2. Multi-turn reuses the session
|
||||
print("[2] Agent:", agent.start("And for a linear scan?"))
|
||||
|
||||
# 3. Local session metadata (cloud usage accumulated)
|
||||
info = managed.retrieve_session()
|
||||
print(f"[3] session={managed.session_id} "
|
||||
f"in={info.get('usage', {}).get('input_tokens', 0)} "
|
||||
f"out={info.get('usage', {}).get('output_tokens', 0)}")
|
||||
@@ -15,6 +15,13 @@ Protocol: MCP 2025-11-25
|
||||
|
||||
from praisonaiagents import Agent, MCP
|
||||
|
||||
# Agent with resumability support (automatic)
|
||||
agent = Agent(
|
||||
name="Resumable Assistant",
|
||||
instructions="You are a helpful assistant with resumable connections.",
|
||||
tools=MCP("https://api.example.com/mcp")
|
||||
)
|
||||
|
||||
# Resumability is automatic - the MCP client:
|
||||
# 1. Tracks event IDs from SSE streams (id: field)
|
||||
# 2. Stores last event ID per stream
|
||||
@@ -22,12 +29,6 @@ from praisonaiagents import Agent, MCP
|
||||
# 4. Respects retry delay from server (retry: field)
|
||||
|
||||
if __name__ == "__main__":
|
||||
agent = Agent(
|
||||
name="Resumable Assistant",
|
||||
instructions="You are a helpful assistant with resumable connections.",
|
||||
tools=MCP("https://api.example.com/mcp"),
|
||||
)
|
||||
|
||||
print("MCP Resumability Example")
|
||||
print("=" * 40)
|
||||
print()
|
||||
|
||||
Loaded 100 of 903 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user