Compare commits

...
39 Commits
Author SHA1 Message Date
Mervin Praison 985a612273 Release v2.7.7 2025-12-30 07:28:15 +00:00
Mervin Praison 9b4cc1d472 Fix: Add async cleanup fixtures to suppress aiohttp unclosed session warnings 2025-12-30 07:12:24 +00:00
Mervin Praison ad5377900b Split test run and output display for better visibility 2025-12-30 07:06:12 +00:00
Mervin Praison a0f2d9d11a Fix debug workflow to properly capture pytest exit code with PIPESTATUS 2025-12-30 06:59:59 +00:00
Mervin Praison 7428bed13f Simplify debug workflow to show full test output 2025-12-30 06:54:04 +00:00
Mervin Praison fbc191c2a2 Update debug workflow to show detailed failure info 2025-12-30 06:47:55 +00:00
Mervin Praison 8a474d680d Fix debug workflow to properly show test failures 2025-12-30 06:41:50 +00:00
Mervin Praison eb120376f7 Update debug workflow to capture full test output with artifact 2025-12-30 06:35:52 +00:00
Mervin Praison d376d88d74 Update debug workflow to capture all test failures 2025-12-30 06:29:42 +00:00
Mervin Praison f0c31ba8ec Add quick debug workflow to identify failing tests 2025-12-30 06:23:46 +00:00
Mervin Praison 439bf42eec Fix: Add pytest_plugins for pytest-asyncio support in conftest.py 2025-12-29 20:50:17 +00:00
Mervin Praison fcaeba6894 Fix: Add sse-starlette dependency and fix JobExecutor event loop issue 2025-12-29 20:43:50 +00:00
Mervin Praison 8a4c2c2c43 Release v2.7.6 2025-12-29 17:28:44 +00:00
Mervin Praison 0b2e6ff69b examples 2025-12-29 16:25:23 +00:00
Mervin Praison 1050d66970 Release v2.7.5 2025-12-29 14:31:52 +00:00
Mervin Praison bf483f3bd6 Release v2.7.4 2025-12-29 13:01:04 +00:00
Mervin Praison 00ee8eb2f3 Release v2.7.3 2025-12-29 12:19:58 +00:00
Mervin Praison 9a5a432d96 Release v2.7.2 2025-12-29 11:40:55 +00:00
Mervin Praison 8cb5bbb605 Release v2.7.2 - update doctor examples with improved check listing and CI formatting
- Add doctor examples to main README with documentation link
- Sort checks by category in list_available_checks()
- Update registry method call from list_checks() to get_all_checks()
- Remove unused results variable in run_environment_checks()
- Fix f-string formatting in CI integration print statement
2025-12-29 02:19:16 +00:00
Mervin Praison 952514d73c Release v2.7.1 2025-12-29 02:15:51 +00:00
Mervin Praison 6e1dc34864 Release v2.7.0 2025-12-29 01:33:40 +00:00
Mervin Praison 820d5c2995 Release v2.6.8 2025-12-29 00:42:47 +00:00
Mervin Praison 0b1b3d3b3e Release v2.6.7 2025-12-29 00:22:52 +00:00
Mervin Praison 59107addc3 Release v2.6.6 2025-12-28 23:51:03 +00:00
Mervin Praison b460ded5e0 Release v2.6.5 2025-12-28 23:02:27 +00:00
Mervin Praison a8967ed200 Release v1.3.1 - add Router class with simplified keyword/pattern-based routing and agent session management
- Bump praisonai-ts version from 1.3.0 to 1.3.1
- Add Router class with simplified keyword/pattern-based routing API (5-line usage)
- Export Router, RouterAgent, createRouter, routeConditions from agent module
- Add SimpleRouterConfig and SimpleRouteConfig types for simplified configuration
- Support both Agent and EnhancedAgent types in router (AnyAgent union type)
- Add Router.chat() method for direct routing
2025-12-28 22:53:04 +00:00
Mervin Praison 9189f42470 Release v2.6.4 2025-12-28 21:47:32 +00:00
Mervin Praison c86f660f66 Release v2.6.3 2025-12-28 07:31:42 +00:00
Mervin Praison a2d181dd74 Release v2.6.2 2025-12-27 07:58:18 +00:00
Mervin Praison 7411fdbb52 Release v2.6.1 2025-12-26 19:41:45 +00:00
Mervin Praison e7a8ce8eb7 Release v2.6.0 2025-12-26 19:31:15 +00:00
Mervin Praison 61fb094306 Release v1.2.3 - add comprehensive CLI feature exports and command definitions
- Bump praisonai-ts version from 1.2.2 to 1.2.3
- Add 18 new command definitions to CLI spec: query-rewrite, prompt-expand, router, context, handoff, vector, observability, voice, reranker, graph-rag, cache, db, scheduler, jobs, checkpoints, fast-context, autonomy, sandbox, repo-map, git, n8n, external-agents, flow, cost, interactive
- Export FileMemory and AutoMemory classes with factory functions and types from memory module
- Export
2025-12-26 18:41:37 +00:00
Mervin Praison 018e8c78ab refactor(ts): update CLI to v1.0.0 spec and change default model to gpt-4o-mini
- Change default agent model from gpt-5-nano to gpt-4o-mini in simple.ts
- Refactor CLI to implement CLI Spec v1.0.0 with lazy command loading
- Add parseArgs() function for spec-compliant argument parsing
- Add executeCommand() for dynamic command module loading
- Add comprehensive command definitions: memory, session, knowledge, skills, mcp, auto, image, research, guardrail, telemetry, planning
- Export CLI_SPEC_VERSION,
2025-12-26 14:07:05 +00:00
Mervin Praison f0f0f653fe Release v2.5.7 2025-12-26 13:31:45 +00:00
Mervin Praison 98a4ff8450 Release v2.5.6 2025-12-26 13:11:09 +00:00
Mervin Praison d6333aaf33 Release v1.2.1 - refactor TypeScript tools to use generic BaseTool
- Bump praisonai-ts version from 1.2.0 to 1.2.1
- Refactor BaseTool to use generics for type-safe input/output parameters
- Update ArxivSearchTool and ArxivDownloadTool to extend generic BaseTool with typed params
- Update MCPTool to extend generic BaseTool
- Change tool method from execute() to run() for consistency
- Export ToolResult, ToolValidationError, validateTool, createTool from base module
- Remove Tool interface export
2025-12-26 11:47:17 +00:00
Mervin Praison 8005094267 update 2025-12-26 08:39:22 +00:00
Mervin Praison 08b21dabe3 Release v2.5.5 2025-12-26 08:16:54 +00:00
Mervin Praison 8c70d840df docs: add knowledge export/import CLI commands to README
- Add knowledge export/import row to features table with CLI link
- Document `praisonai knowledge export <file.json>` command
- Document `praisonai knowledge import <file.json>` command
2025-12-26 06:53:20 +00:00
510 changed files with 97775 additions and 1369 deletions

No files matched your search

+68
View File
@@ -0,0 +1,68 @@
name: Quick Debug Tests
on:
push:
branches: [ main ]
workflow_dispatch:
jobs:
debug-tests:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.11
- name: Install UV
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install dependencies
run: |
cd src/praisonai
uv pip install --system ."[ui,gradio,api,agentops,google,openai,anthropic,cohere,chat,code,realtime,call,crewai,autogen]"
uv pip install --system duckduckgo_search
uv pip install --system pytest pytest-cov pytest-asyncio pytest-timeout
uv pip install --system "praisonaiagents[knowledge]"
- name: Set environment variables
run: |
echo "OPENAI_API_KEY=sk-test-key-for-github-actions-testing-only-not-real" >> $GITHUB_ENV
echo "OPENAI_API_BASE=https://api.openai.com/v1" >> $GITHUB_ENV
echo "OPENAI_MODEL_NAME=gpt-4o-mini" >> $GITHUB_ENV
echo "LOGLEVEL=WARNING" >> $GITHUB_ENV
echo "PYTHONPATH=${{ github.workspace }}/src/praisonai-agents:$PYTHONPATH" >> $GITHUB_ENV
- name: Run Unit Tests
id: pytest
run: |
cd src/praisonai
# Run pytest and save output, don't fail immediately
python -m pytest tests/unit/ -v --tb=short > test_output.txt 2>&1 || echo "TESTS_FAILED=true" >> $GITHUB_ENV
- name: Show Test Results
if: always()
run: |
cd src/praisonai
echo "=========================================="
echo "=== FULL TEST OUTPUT ==="
echo "=========================================="
cat test_output.txt
echo ""
echo "=========================================="
echo "=== FAILED TESTS SUMMARY ==="
echo "=========================================="
grep "^FAILED" test_output.txt || echo "No FAILED lines"
echo ""
# Fail if tests failed
if [ "$TESTS_FAILED" = "true" ]; then
echo "Tests failed!"
exit 1
fi
+523 -170
View File
@@ -35,46 +35,108 @@ PraisonAI is a production-ready Multi-AI Agents framework with self-reflection,
---
> **Quick Paths:**
> - 🚀 **New here?** → [Quick Start](#-quick-start)
> - 📦 **Installing?** → [Installation](#-installation)
> - 💻 **Python SDK?** → [Python Examples](#-using-python-code)
> - 🎯 **CLI user?** → [CLI Reference](#-cli--no-code-interface)
> - 🔧 **Need config?** → [Configuration](#-configuration--integration)
> - 🤝 **Contributing?** → [Development](#-development)
---
## 📑 Table of Contents
### Getting Started
- [⚡ Performance](#-performance)
- [🚀 Quick Start](#-quick-start)
- [📦 Installation](#-installation)
- [Python SDK](#python-sdk)
- [JavaScript SDK](#javascript-sdk)
- [💻 Usage](#-usage)
- [Python Code Examples](#python-code-examples)
- [CLI / No-Code Interface](#cli--no-code-interface)
- [JavaScript Code Examples](#javascript-code-examples)
- [Environment Variables](#environment-variables)
### Core Concepts
- [✨ Key Features](#-key-features)
- [🌐 Supported Providers](#-supported-providers)
### Python SDK
- [📘 Python Examples](#-using-python-code)
- [1. Single Agent](#1-single-agent)
- [2. Multi Agents](#2-multi-agents)
- [3. Planning Mode](#3-agent-with-planning-mode)
- [4. Deep Research](#4-deep-research-agent)
- [5. Query Rewriter](#5-query-rewriter-agent)
- [6. Agent Memory](#6-agent-memory-zero-dependencies)
- [7. Rules & Instructions](#7-rules--instructions)
- [8. Auto-Generated Memories](#8-auto-generated-memories)
- [9. Agentic Workflows](#9-agentic-workflows)
- [10. Hooks](#10-hooks)
- [11. Shadow Git Checkpoints](#11-shadow-git-checkpoints)
- [12. Background Tasks](#12-background-tasks)
- [13. Policy Engine](#13-policy-engine)
- [14. Thinking Budgets](#14-thinking-budgets)
- [15. Output Styles](#15-output-styles)
- [16. Context Compaction](#16-context-compaction)
- [17. Field Names Reference](#17-field-names-reference-a-i-g-s)
- [18. Extended agents.yaml](#18-extended-agentsyaml-with-workflow-patterns)
- [19. MCP Protocol](#19-mcp-model-context-protocol)
- [20. A2A Protocol](#20-a2a-agent2agent-protocol)
- [🛠️ Custom Tools](#️-custom-tools)
### JavaScript SDK
- [💻 JavaScript Examples](#-using-javascript-code)
### CLI Reference
- [🎯 CLI Overview](#-cli--no-code-interface)
- [Auto Mode](#auto-mode)
- [Interactive Mode](#interactive-mode-cli)
- [Deep Research CLI](#deep-research-cli)
- [Planning Mode CLI](#planning-mode-cli)
- [Memory CLI](#memory-cli)
- [Workflow CLI](#workflow-cli)
- [Knowledge CLI](#knowledge-cli)
- [Session CLI](#session-cli)
- [Tools CLI](#tools-cli)
- [MCP Config CLI](#mcp-config-cli)
- [External Agents CLI](#external-agents-cli)
- [CLI Features Summary](#cli-features)
### Configuration
- [🔧 Configuration & Integration](#-configuration--integration)
- [Ollama Integration](#ollama-integration)
- [Groq Integration](#groq-integration)
- [100+ Models Support](#100-models-support)
- [📋 Workflows](#-workflows)
- [Workflow Patterns](#workflow-patterns)
- [YAML Configuration](#yaml-configuration)
- [Agents Playbook](#agents-playbook)
- [🧠 Memory & Context](#-memory--context)
- [📋 Agents Playbook](#-agents-playbook)
### Advanced Features
- [🔬 Advanced Features](#-advanced-features)
- [Research & Intelligence](#research--intelligence)
- [Memory & Caching](#memory--caching)
- [Planning & Workflows](#planning--workflows)
- [Specialised Agents](#specialised-agents)
- [MCP Protocol](#mcp-protocol)
- [A2A & A2UI Protocols](#a2a--a2ui-protocols)
- [Safety & Control](#safety--control)
- [Developer Tools](#developer-tools)
### Architecture
- [📊 Process Types & Patterns](#-process-types--patterns)
- [Sequential Process](#sequential-process)
- [Hierarchical Process](#hierarchical-process)
- [Workflow Process](#workflow-process)
- [Agentic Patterns](#agentic-patterns)
### Data & Persistence
- [💾 Persistence (Databases)](#-persistence-databases)
- [📚 Knowledge & Retrieval (RAG)](#-knowledge--retrieval-rag)
- [🔧 Tools Table](#-tools-table)
### Learning & Community
- [🎓 Video Tutorials](#-video-tutorials)
- [⭐ Star History](#-star-history)
- [👥 Contributing](#-contributing)
- [🔧 Development](#-development)
- [❓ FAQ & Troubleshooting](#-faq--troubleshooting)
---
@@ -143,6 +205,30 @@ pip install praisonai
npm install praisonai
```
### Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `OPENAI_API_KEY` | Yes* | OpenAI API key |
| `ANTHROPIC_API_KEY` | No | Anthropic Claude API key |
| `GOOGLE_API_KEY` | No | Google Gemini API key |
| `GROQ_API_KEY` | No | Groq API key |
| `OPENAI_BASE_URL` | No | Custom API endpoint (for Ollama, Groq, etc.) |
> *At least one LLM provider API key is required.
```bash
# Set your API key
export OPENAI_API_KEY=your_key_here
# For Ollama (local models)
export OPENAI_BASE_URL=http://localhost:11434/v1
# For Groq
export OPENAI_API_KEY=your_groq_key
export OPENAI_BASE_URL=https://api.groq.com/openai/v1
```
---
## 💻 Usage
@@ -169,147 +255,263 @@ npm install praisonai
## ✨ Key Features
<details open>
<summary><strong>🤖 Core Agents</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| **🤖 Core Agents** | | |
| ↳ Single Agent | [Example](examples/python/agents/single-agent.py) | [📖](https://docs.praison.ai/agents/single) |
| ↳ Multi Agents | [Example](examples/python/general/mini_agents_example.py) | [📖](https://docs.praison.ai/concepts/agents) |
| ↳ Auto Agents | [Example](examples/python/general/auto_agents_example.py) | [📖](https://docs.praison.ai/features/autoagents) |
| ↳ Self Reflection AI Agents | [Example](examples/python/concepts/self-reflection-details.py) | [📖](https://docs.praison.ai/features/selfreflection) |
| ↳ Reasoning AI Agents | [Example](examples/python/concepts/reasoning-extraction.py) | [📖](https://docs.praison.ai/features/reasoning) |
| ↳ Multi Modal AI Agents | [Example](examples/python/general/multimodal.py) | [📖](https://docs.praison.ai/features/multimodal) |
| **🔄 Workflows** | | |
| ↳ Simple Workflow | [Example](examples/python/workflows/simple_workflow.py) | [📖](https://docs.praison.ai/features/workflows) |
| ↳ Workflow with Agents | [Example](examples/python/workflows/workflow_with_agents.py) | [📖](https://docs.praison.ai/features/workflows) |
| ↳ Agentic Routing (`route()`) | [Example](examples/python/workflows/workflow_routing.py) | [📖](https://docs.praison.ai/features/routing) |
| ↳ Parallel Execution (`parallel()`) | [Example](examples/python/workflows/workflow_parallel.py) | [📖](https://docs.praison.ai/features/parallelisation) |
| ↳ Loop over List/CSV (`loop()`) | [Example](examples/python/workflows/workflow_loop_csv.py) | [📖](https://docs.praison.ai/features/repetitive) |
| ↳ Evaluator-Optimizer (`repeat()`) | [Example](examples/python/workflows/workflow_repeat.py) | [📖](https://docs.praison.ai/features/evaluator-optimiser) |
| ↳ Conditional Steps | [Example](examples/python/workflows/workflow_conditional.py) | [📖](https://docs.praison.ai/features/workflows) |
| ↳ Workflow Branching | [Example](examples/python/workflows/workflow_branching.py) | [📖](https://docs.praison.ai/features/workflows) |
| ↳ Workflow Early Stop | [Example](examples/python/workflows/workflow_early_stop.py) | [📖](https://docs.praison.ai/features/workflows) |
| ↳ Workflow Checkpoints | [Example](examples/python/workflows/workflow_checkpoints.py) | [📖](https://docs.praison.ai/features/workflows) |
| **💻 Code & Development** | | |
| ↳ Code Interpreter Agents | [Example](examples/python/agents/code-agent.py) | [📖](https://docs.praison.ai/features/codeagent) |
| ↳ AI Code Editing Tools | [Example](examples/python/code/code_editing_example.py) | [📖](https://docs.praison.ai/code/editing) |
| ↳ External Agents (All) | [Example](examples/python/code/external_agents_example.py) | [📖](https://docs.praison.ai/code/external-agents) |
| ↳ Claude Code CLI | [Example](examples/python/code/claude_code_example.py) | [📖](https://docs.praison.ai/code/claude-code) |
| ↳ Gemini CLI | [Example](examples/python/code/gemini_cli_example.py) | [📖](https://docs.praison.ai/code/gemini-cli) |
| ↳ Codex CLI | [Example](examples/python/code/codex_cli_example.py) | [📖](https://docs.praison.ai/code/codex-cli) |
| ↳ Cursor CLI | [Example](examples/python/code/cursor_cli_example.py) | [📖](https://docs.praison.ai/code/cursor-cli) |
| **🧠 Memory & Knowledge** | | |
| ↳ Memory (Short & Long Term) | [Example](examples/python/general/memory_example.py) | [📖](https://docs.praison.ai/concepts/memory) |
| ↳ File-Based Memory | [Example](examples/python/general/memory_example.py) | [📖](https://docs.praison.ai/concepts/memory) |
| ↳ Claude Memory Tool | [Example](#claude-memory-tool-cli) | [📖](https://docs.praison.ai/features/claude-memory-tool) |
| ↳ Add Custom Knowledge | [Example](examples/python/concepts/knowledge-agents.py) | [📖](https://docs.praison.ai/features/knowledge) |
| ↳ RAG Agents | [Example](examples/python/concepts/rag-agents.py) | [📖](https://docs.praison.ai/features/rag) |
| ↳ Chat with PDF Agents | [Example](examples/python/concepts/chat-with-pdf.py) | [📖](https://docs.praison.ai/features/chat-with-pdf) |
| ↳ Data Readers (PDF, DOCX, etc.) | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-readers-api) |
| ↳ Vector Store Selection | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-vector-store-api) |
| ↳ Retrieval Strategies | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-retrieval-api) |
| ↳ Rerankers | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-reranker-api) |
| ↳ Index Types (Vector/Keyword/Hybrid) | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-index-api) |
| ↳ Query Engines (Sub-Question, etc.) | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-query-engine-api) |
| **🔬 Research & Intelligence** | | |
| ↳ Deep Research Agents | [Example](examples/python/agents/research-agent.py) | [📖](https://docs.praison.ai/agents/deep-research) |
| ↳ Query Rewriter Agent | [Example](#5-query-rewriter-agent) | [📖](https://docs.praison.ai/agents/query-rewriter) |
| ↳ Native Web Search | [Example](examples/python/agents/websearch-agent.py) | [📖](https://docs.praison.ai/agents/websearch) |
| ↳ Built-in Search Tools | [Example](examples/python/agents/websearch-agent.py) | [📖](https://docs.praison.ai/tools/tavily) |
| ↳ Unified Web Search | [Example](src/praisonai-agents/examples/web_search_example.py) | [📖](https://docs.praison.ai/tools/web-search) |
| ↳ Web Fetch (Anthropic) | [Example](#web-search-web-fetch--prompt-caching) | [📖](https://docs.praison.ai/features/model-capabilities) |
| **📋 Planning & Execution** | | |
| ↳ Planning Mode | [Example](examples/python/agents/planning-agent.py) | [📖](https://docs.praison.ai/features/planning-mode) |
| ↳ Planning Tools | [Example](#3-agent-with-planning-mode) | [📖](https://docs.praison.ai/features/planning-mode) |
| ↳ Planning Reasoning | [Example](#3-agent-with-planning-mode) | [📖](https://docs.praison.ai/features/planning-mode) |
| ↳ Prompt Chaining | [Example](examples/python/general/prompt_chaining.py) | [📖](https://docs.praison.ai/features/promptchaining) |
| ↳ Evaluator Optimiser | [Example](examples/python/general/evaluator-optimiser.py) | [📖](https://docs.praison.ai/features/evaluator-optimiser) |
| ↳ Orchestrator Workers | [Example](examples/python/general/orchestrator-workers.py) | [📖](https://docs.praison.ai/features/orchestrator-worker) |
| **👥 Specialized Agents** | | |
| ↳ Data Analyst Agent | [Example](examples/python/agents/data-analyst-agent.py) | [📖](https://docs.praison.ai/agents/data-analyst) |
| ↳ Finance Agent | [Example](examples/python/agents/finance-agent.py) | [📖](https://docs.praison.ai/agents/finance) |
| ↳ Shopping Agent | [Example](examples/python/agents/shopping-agent.py) | [📖](https://docs.praison.ai/agents/shopping) |
| ↳ Recommendation Agent | [Example](examples/python/agents/recommendation-agent.py) | [📖](https://docs.praison.ai/agents/recommendation) |
| ↳ Wikipedia Agent | [Example](examples/python/agents/wikipedia-agent.py) | [📖](https://docs.praison.ai/agents/wikipedia) |
| ↳ Programming Agent | [Example](examples/python/agents/programming-agent.py) | [📖](https://docs.praison.ai/agents/programming) |
| ↳ Math Agents | [Example](examples/python/agents/math-agent.py) | [📖](https://docs.praison.ai/features/mathagent) |
| ↳ Markdown Agent | [Example](examples/python/agents/markdown-agent.py) | [📖](https://docs.praison.ai/agents/markdown) |
| ↳ Prompt Expander Agent | [Example](#prompt-expansion) | [📖](https://docs.praison.ai/agents/prompt-expander) |
| **🎨 Media & Multimodal** | | |
| ↳ Image Generation Agent | [Example](examples/python/image/image-agent.py) | [📖](https://docs.praison.ai/features/image-generation) |
| ↳ Image to Text Agent | [Example](examples/python/agents/image-to-text-agent.py) | [📖](https://docs.praison.ai/agents/image-to-text) |
| ↳ Video Agent | [Example](examples/python/agents/video-agent.py) | [📖](https://docs.praison.ai/agents/video) |
| ↳ Camera Integration | [Example](examples/python/camera/) | [📖](https://docs.praison.ai/features/camera-integration) |
| **🔌 Protocols & Integration** | | |
| ↳ MCP Transports | [Example](examples/python/mcp/mcp-transports-overview.py) | [📖](https://docs.praison.ai/mcp/transports) |
| ↳ WebSocket MCP | [Example](examples/python/mcp/websocket-mcp.py) | [📖](https://docs.praison.ai/mcp/sse-transport) |
| ↳ MCP Security | [Example](examples/python/mcp/mcp-security.py) | [📖](https://docs.praison.ai/mcp/transports) |
| ↳ MCP Resumability | [Example](examples/python/mcp/mcp-resumability.py) | [📖](https://docs.praison.ai/mcp/sse-transport) |
| ↳ MCP Config Management | [Example](#mcp-config-cli) | [📖](https://docs.praison.ai/docs/cli/mcp) |
| ↳ LangChain Integrated Agents | [Example](examples/python/general/langchain_example.py) | [📖](https://docs.praison.ai/features/langchain) |
| **🛡️ Safety & Control** | | |
| ↳ Guardrails | [Example](examples/python/guardrails/comprehensive-guardrails-example.py) | [📖](https://docs.praison.ai/features/guardrails) |
| ↳ Human Approval | [Example](examples/python/general/human_approval_example.py) | [📖](https://docs.praison.ai/features/approval) |
| ↳ Rules & Instructions | [Example](#6-rules--instructions) | [📖](https://docs.praison.ai/features/rules) |
| **⚙️ Advanced Features** | | |
| ↳ Async & Parallel Processing | [Example](examples/python/general/async_example.py) | [📖](https://docs.praison.ai/features/async) |
| ↳ Parallelisation | [Example](examples/python/general/parallelisation.py) | [📖](https://docs.praison.ai/features/parallelisation) |
| ↳ Repetitive Agents | [Example](examples/python/concepts/repetitive-agents.py) | [📖](https://docs.praison.ai/features/repetitive) |
| ↳ Agent Handoffs | [Example](examples/python/handoff/handoff_basic.py) | [📖](https://docs.praison.ai/features/handoffs) |
| ↳ Stateful Agents | [Example](examples/python/stateful/workflow-state-example.py) | [📖](https://docs.praison.ai/features/stateful-agents) |
| ↳ Autonomous Workflow | [Example](examples/python/general/autonomous-agent.py) | [📖](https://docs.praison.ai/features/autonomous-workflow) |
| ↳ Structured Output Agents | [Example](examples/python/general/structured_agents_example.py) | [📖](https://docs.praison.ai/features/structured) |
| ↳ Model Router | [Example](examples/python/agents/router-agent-cost-optimization.py) | [📖](https://docs.praison.ai/features/model-router) |
| ↳ Prompt Caching | [Example](#web-search-web-fetch--prompt-caching) | [📖](https://docs.praison.ai/features/model-capabilities) |
| ↳ Fast Context | [Example](examples/context/00_agent_fast_context_basic.py) | [📖](https://docs.praison.ai/features/fast-context) |
| **🛠️ Tools & Configuration** | | |
| ↳ 100+ Custom Tools | [Example](examples/python/general/tools_example.py) | [📖](https://docs.praison.ai/tools/tools) |
| ↳ YAML Configuration | [Example](examples/cookbooks/yaml/secondary_market_research_agents.yaml) | [📖](https://docs.praison.ai/developers/agents-playbook) |
| ↳ 100+ LLM Support | [Example](examples/python/providers/openai/openai_gpt4_example.py) | [📖](https://docs.praison.ai/models) |
| ↳ Callback Agents | [Example](examples/python/general/advanced-callback-systems.py) | [📖](https://docs.praison.ai/features/callbacks) |
| ↳ Hooks | [Example](#9-hooks) | [📖](https://docs.praison.ai/features/hooks) |
| ↳ Middleware System | [Example](examples/middleware/basic_middleware.py) | [📖](https://docs.praison.ai/features/middleware) |
| ↳ Configurable Model | [Example](examples/middleware/configurable_model.py) | [📖](https://docs.praison.ai/features/configurable-model) |
| ↳ Rate Limiter | [Example](examples/middleware/rate_limiter.py) | [📖](https://docs.praison.ai/features/rate-limiter) |
| ↳ Injected Tool State | [Example](examples/middleware/injected_state.py) | [📖](https://docs.praison.ai/features/injected-state) |
| ↳ Shadow Git Checkpoints | [Example](#10-shadow-git-checkpoints) | [📖](https://docs.praison.ai/features/checkpoints) |
| ↳ Background Tasks | [Example](examples/background/basic_background.py) | [📖](https://docs.praison.ai/features/background-tasks) |
| ↳ Policy Engine | [Example](examples/policy/basic_policy.py) | [📖](https://docs.praison.ai/features/policy-engine) |
| ↳ Thinking Budgets | [Example](examples/thinking/basic_thinking.py) | [📖](https://docs.praison.ai/features/thinking-budgets) |
| ↳ Output Styles | [Example](examples/output/basic_output.py) | [📖](https://docs.praison.ai/features/output-styles) |
| ↳ Context Compaction | [Example](examples/compaction/basic_compaction.py) | [📖](https://docs.praison.ai/features/context-compaction) |
| **📊 Monitoring & Management** | | |
| ↳ Sessions Management | [Example](examples/python/sessions/comprehensive-session-management.py) | [📖](https://docs.praison.ai/features/sessions) |
| ↳ Auto-Save Sessions | [Example](#session-management-python) | [📖](https://docs.praison.ai/docs/cli/session) |
| ↳ History in Context | [Example](#session-management-python) | [📖](https://docs.praison.ai/docs/cli/session) |
| ↳ Telemetry | [Example](examples/python/telemetry/production-telemetry-example.py) | [📖](https://docs.praison.ai/features/telemetry) |
| ↳ Project Docs (.praison/docs/) | [Example](#docs-cli) | [📖](https://docs.praison.ai/docs/cli/docs) |
| ↳ AI Commit Messages | [Example](#ai-commit-cli) | [📖](https://docs.praison.ai/docs/cli/commit) |
| ↳ @Mentions in Prompts | [Example](#mentions-in-prompts) | [📖](https://docs.praison.ai/docs/cli/mentions) |
| **🖥️ CLI Features** | | |
| ↳ Slash Commands | [Example](examples/python/cli/slash_commands_example.py) | [📖](https://docs.praison.ai/docs/cli/slash-commands) |
| ↳ Autonomy Modes | [Example](examples/python/cli/autonomy_modes_example.py) | [📖](https://docs.praison.ai/docs/cli/autonomy-modes) |
| ↳ Cost Tracking | [Example](examples/python/cli/cost_tracking_example.py) | [📖](https://docs.praison.ai/docs/cli/cost-tracking) |
| ↳ Repository Map | [Example](examples/python/cli/repo_map_example.py) | [📖](https://docs.praison.ai/docs/cli/repo-map) |
| ↳ Interactive TUI | [Example](examples/python/cli/interactive_tui_example.py) | [📖](https://docs.praison.ai/docs/cli/interactive-tui) |
| ↳ Git Integration | [Example](examples/python/cli/git_integration_example.py) | [📖](https://docs.praison.ai/docs/cli/git-integration) |
| ↳ Sandbox Execution | [Example](examples/python/cli/sandbox_execution_example.py) | [📖](https://docs.praison.ai/docs/cli/sandbox-execution) |
| ↳ CLI Compare | [Example](examples/compare/cli_compare_basic.py) | [📖](https://docs.praison.ai/docs/cli/compare) |
| ↳ Profile/Benchmark | [Example](#profile-benchmark) | [📖](https://docs.praison.ai/docs/cli/profile) |
| ↳ Auto Mode | [Example](#auto-mode) | [📖](https://docs.praison.ai/docs/cli/auto) |
| ↳ Init | [Example](#init) | [📖](https://docs.praison.ai/docs/cli/init) |
| ↳ File Input | [Example](#file-input) | [📖](https://docs.praison.ai/docs/cli/file-input) |
| ↳ Final Agent | [Example](#final-agent) | [📖](https://docs.praison.ai/docs/cli/final-agent) |
| ↳ Max Tokens | [Example](#max-tokens) | [📖](https://docs.praison.ai/docs/cli/max-tokens) |
| **🧪 Evaluation** | | |
| ↳ Accuracy Evaluation | [Example](examples/eval/accuracy_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| ↳ Performance Evaluation | [Example](examples/eval/performance_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| ↳ Reliability Evaluation | [Example](examples/eval/reliability_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| ↳ Criteria Evaluation | [Example](examples/eval/criteria_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| **🎯 Agent Skills** | | |
| ↳ Skills Management | [Example](examples/skills/basic_skill_usage.py) | [📖](https://docs.praison.ai/features/skills) |
| ↳ Custom Skills | [Example](examples/skills/custom_skill_example.py) | [📖](https://docs.praison.ai/features/skills) |
| **⏰ 24/7 Scheduling** | | |
| ↳ Agent Scheduler | [Example](examples/python/scheduled_agents/news_checker_live.py) | [📖](https://docs.praison.ai/docs/cli/scheduler) |
| Single Agent | [Example](examples/python/agents/single-agent.py) | [📖](https://docs.praison.ai/agents/single) |
| Multi Agents | [Example](examples/python/general/mini_agents_example.py) | [📖](https://docs.praison.ai/concepts/agents) |
| Auto Agents | [Example](examples/python/general/auto_agents_example.py) | [📖](https://docs.praison.ai/features/autoagents) |
| Self Reflection AI Agents | [Example](examples/python/concepts/self-reflection-details.py) | [📖](https://docs.praison.ai/features/selfreflection) |
| Reasoning AI Agents | [Example](examples/python/concepts/reasoning-extraction.py) | [📖](https://docs.praison.ai/features/reasoning) |
| Multi Modal AI Agents | [Example](examples/python/general/multimodal.py) | [📖](https://docs.praison.ai/features/multimodal) |
</details>
<details>
<summary><strong>🔄 Workflows</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Simple Workflow | [Example](examples/python/workflows/simple_workflow.py) | [📖](https://docs.praison.ai/features/workflows) |
| Workflow with Agents | [Example](examples/python/workflows/workflow_with_agents.py) | [📖](https://docs.praison.ai/features/workflows) |
| Agentic Routing (`route()`) | [Example](examples/python/workflows/workflow_routing.py) | [📖](https://docs.praison.ai/features/routing) |
| Parallel Execution (`parallel()`) | [Example](examples/python/workflows/workflow_parallel.py) | [📖](https://docs.praison.ai/features/parallelisation) |
| Loop over List/CSV (`loop()`) | [Example](examples/python/workflows/workflow_loop_csv.py) | [📖](https://docs.praison.ai/features/repetitive) |
| Evaluator-Optimizer (`repeat()`) | [Example](examples/python/workflows/workflow_repeat.py) | [📖](https://docs.praison.ai/features/evaluator-optimiser) |
| Conditional Steps | [Example](examples/python/workflows/workflow_conditional.py) | [📖](https://docs.praison.ai/features/workflows) |
| Workflow Branching | [Example](examples/python/workflows/workflow_branching.py) | [📖](https://docs.praison.ai/features/workflows) |
| Workflow Early Stop | [Example](examples/python/workflows/workflow_early_stop.py) | [📖](https://docs.praison.ai/features/workflows) |
| Workflow Checkpoints | [Example](examples/python/workflows/workflow_checkpoints.py) | [📖](https://docs.praison.ai/features/workflows) |
</details>
<details>
<summary><strong>💻 Code & Development</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Code Interpreter Agents | [Example](examples/python/agents/code-agent.py) | [📖](https://docs.praison.ai/features/codeagent) |
| AI Code Editing Tools | [Example](examples/python/code/code_editing_example.py) | [📖](https://docs.praison.ai/code/editing) |
| External Agents (All) | [Example](examples/python/code/external_agents_example.py) | [📖](https://docs.praison.ai/code/external-agents) |
| Claude Code CLI | [Example](examples/python/code/claude_code_example.py) | [📖](https://docs.praison.ai/code/claude-code) |
| Gemini CLI | [Example](examples/python/code/gemini_cli_example.py) | [📖](https://docs.praison.ai/code/gemini-cli) |
| Codex CLI | [Example](examples/python/code/codex_cli_example.py) | [📖](https://docs.praison.ai/code/codex-cli) |
| Cursor CLI | [Example](examples/python/code/cursor_cli_example.py) | [📖](https://docs.praison.ai/code/cursor-cli) |
</details>
<details>
<summary><strong>🧠 Memory & Knowledge</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Memory (Short & Long Term) | [Example](examples/python/general/memory_example.py) | [📖](https://docs.praison.ai/concepts/memory) |
| File-Based Memory | [Example](examples/python/general/memory_example.py) | [📖](https://docs.praison.ai/concepts/memory) |
| Claude Memory Tool | [Example](#claude-memory-tool-cli) | [📖](https://docs.praison.ai/features/claude-memory-tool) |
| Add Custom Knowledge | [Example](examples/python/concepts/knowledge-agents.py) | [📖](https://docs.praison.ai/features/knowledge) |
| RAG Agents | [Example](examples/python/concepts/rag-agents.py) | [📖](https://docs.praison.ai/features/rag) |
| Chat with PDF Agents | [Example](examples/python/concepts/chat-with-pdf.py) | [📖](https://docs.praison.ai/features/chat-with-pdf) |
| Data Readers (PDF, DOCX, etc.) | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-readers-api) |
| Vector Store Selection | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-vector-store-api) |
| Retrieval Strategies | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-retrieval-api) |
| Rerankers | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-reranker-api) |
| Index Types (Vector/Keyword/Hybrid) | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-index-api) |
| Query Engines (Sub-Question, etc.) | [CLI](#knowledge-cli) | [📖](https://docs.praison.ai/api/praisonai/knowledge-query-engine-api) |
</details>
<details>
<summary><strong>🔬 Research & Intelligence</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Deep Research Agents | [Example](examples/python/agents/research-agent.py) | [📖](https://docs.praison.ai/agents/deep-research) |
| Query Rewriter Agent | [Example](#5-query-rewriter-agent) | [📖](https://docs.praison.ai/agents/query-rewriter) |
| Native Web Search | [Example](examples/python/agents/websearch-agent.py) | [📖](https://docs.praison.ai/agents/websearch) |
| Built-in Search Tools | [Example](examples/python/agents/websearch-agent.py) | [📖](https://docs.praison.ai/tools/tavily) |
| Unified Web Search | [Example](src/praisonai-agents/examples/web_search_example.py) | [📖](https://docs.praison.ai/tools/web-search) |
| Web Fetch (Anthropic) | [Example](#web-search-web-fetch--prompt-caching) | [📖](https://docs.praison.ai/features/model-capabilities) |
</details>
<details>
<summary><strong>📋 Planning & Execution</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Planning Mode | [Example](examples/python/agents/planning-agent.py) | [📖](https://docs.praison.ai/features/planning-mode) |
| Planning Tools | [Example](#3-agent-with-planning-mode) | [📖](https://docs.praison.ai/features/planning-mode) |
| Planning Reasoning | [Example](#3-agent-with-planning-mode) | [📖](https://docs.praison.ai/features/planning-mode) |
| Prompt Chaining | [Example](examples/python/general/prompt_chaining.py) | [📖](https://docs.praison.ai/features/promptchaining) |
| Evaluator Optimiser | [Example](examples/python/general/evaluator-optimiser.py) | [📖](https://docs.praison.ai/features/evaluator-optimiser) |
| Orchestrator Workers | [Example](examples/python/general/orchestrator-workers.py) | [📖](https://docs.praison.ai/features/orchestrator-worker) |
</details>
<details>
<summary><strong>👥 Specialized Agents</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Data Analyst Agent | [Example](examples/python/agents/data-analyst-agent.py) | [📖](https://docs.praison.ai/agents/data-analyst) |
| Finance Agent | [Example](examples/python/agents/finance-agent.py) | [📖](https://docs.praison.ai/agents/finance) |
| Shopping Agent | [Example](examples/python/agents/shopping-agent.py) | [📖](https://docs.praison.ai/agents/shopping) |
| Recommendation Agent | [Example](examples/python/agents/recommendation-agent.py) | [📖](https://docs.praison.ai/agents/recommendation) |
| Wikipedia Agent | [Example](examples/python/agents/wikipedia-agent.py) | [📖](https://docs.praison.ai/agents/wikipedia) |
| Programming Agent | [Example](examples/python/agents/programming-agent.py) | [📖](https://docs.praison.ai/agents/programming) |
| Math Agents | [Example](examples/python/agents/math-agent.py) | [📖](https://docs.praison.ai/features/mathagent) |
| Markdown Agent | [Example](examples/python/agents/markdown-agent.py) | [📖](https://docs.praison.ai/agents/markdown) |
| Prompt Expander Agent | [Example](#prompt-expansion) | [📖](https://docs.praison.ai/agents/prompt-expander) |
</details>
<details>
<summary><strong>🎨 Media & Multimodal</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Image Generation Agent | [Example](examples/python/image/image-agent.py) | [📖](https://docs.praison.ai/features/image-generation) |
| Image to Text Agent | [Example](examples/python/agents/image-to-text-agent.py) | [📖](https://docs.praison.ai/agents/image-to-text) |
| Video Agent | [Example](examples/python/agents/video-agent.py) | [📖](https://docs.praison.ai/agents/video) |
| Camera Integration | [Example](examples/python/camera/) | [📖](https://docs.praison.ai/features/camera-integration) |
</details>
<details>
<summary><strong>🔌 Protocols & Integration</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| MCP Transports | [Example](examples/python/mcp/mcp-transports-overview.py) | [📖](https://docs.praison.ai/mcp/transports) |
| WebSocket MCP | [Example](examples/python/mcp/websocket-mcp.py) | [📖](https://docs.praison.ai/mcp/sse-transport) |
| MCP Security | [Example](examples/python/mcp/mcp-security.py) | [📖](https://docs.praison.ai/mcp/transports) |
| MCP Resumability | [Example](examples/python/mcp/mcp-resumability.py) | [📖](https://docs.praison.ai/mcp/sse-transport) |
| MCP Config Management | [Example](#mcp-config-cli) | [📖](https://docs.praison.ai/docs/cli/mcp) |
| LangChain Integrated Agents | [Example](examples/python/general/langchain_example.py) | [📖](https://docs.praison.ai/features/langchain) |
</details>
<details>
<summary><strong>🛡️ Safety & Control</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Guardrails | [Example](examples/python/guardrails/comprehensive-guardrails-example.py) | [📖](https://docs.praison.ai/features/guardrails) |
| Human Approval | [Example](examples/python/general/human_approval_example.py) | [📖](https://docs.praison.ai/features/approval) |
| Rules & Instructions | [Example](#7-rules--instructions) | [📖](https://docs.praison.ai/features/rules) |
</details>
<details>
<summary><strong>⚙️ Advanced Features</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Async & Parallel Processing | [Example](examples/python/general/async_example.py) | [📖](https://docs.praison.ai/features/async) |
| Parallelisation | [Example](examples/python/general/parallelisation.py) | [📖](https://docs.praison.ai/features/parallelisation) |
| Repetitive Agents | [Example](examples/python/concepts/repetitive-agents.py) | [📖](https://docs.praison.ai/features/repetitive) |
| Agent Handoffs | [Example](examples/python/handoff/handoff_basic.py) | [📖](https://docs.praison.ai/features/handoffs) |
| Stateful Agents | [Example](examples/python/stateful/workflow-state-example.py) | [📖](https://docs.praison.ai/features/stateful-agents) |
| Autonomous Workflow | [Example](examples/python/general/autonomous-agent.py) | [📖](https://docs.praison.ai/features/autonomous-workflow) |
| Structured Output Agents | [Example](examples/python/general/structured_agents_example.py) | [📖](https://docs.praison.ai/features/structured) |
| Model Router | [Example](examples/python/agents/router-agent-cost-optimization.py) | [📖](https://docs.praison.ai/features/model-router) |
| Prompt Caching | [Example](#web-search-web-fetch--prompt-caching) | [📖](https://docs.praison.ai/features/model-capabilities) |
| Fast Context | [Example](examples/context/00_agent_fast_context_basic.py) | [📖](https://docs.praison.ai/features/fast-context) |
</details>
<details>
<summary><strong>🛠️ Tools & Configuration</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| 100+ Custom Tools | [Example](examples/python/general/tools_example.py) | [📖](https://docs.praison.ai/tools/tools) |
| YAML Configuration | [Example](examples/cookbooks/yaml/secondary_market_research_agents.yaml) | [📖](https://docs.praison.ai/developers/agents-playbook) |
| 100+ LLM Support | [Example](examples/python/providers/openai/openai_gpt4_example.py) | [📖](https://docs.praison.ai/models) |
| Callback Agents | [Example](examples/python/general/advanced-callback-systems.py) | [📖](https://docs.praison.ai/features/callbacks) |
| Hooks | [Example](#10-hooks) | [📖](https://docs.praison.ai/features/hooks) |
| Middleware System | [Example](examples/middleware/basic_middleware.py) | [📖](https://docs.praison.ai/features/middleware) |
| Configurable Model | [Example](examples/middleware/configurable_model.py) | [📖](https://docs.praison.ai/features/configurable-model) |
| Rate Limiter | [Example](examples/middleware/rate_limiter.py) | [📖](https://docs.praison.ai/features/rate-limiter) |
| Injected Tool State | [Example](examples/middleware/injected_state.py) | [📖](https://docs.praison.ai/features/injected-state) |
| Shadow Git Checkpoints | [Example](#11-shadow-git-checkpoints) | [📖](https://docs.praison.ai/features/checkpoints) |
| Background Tasks | [Example](examples/background/basic_background.py) | [📖](https://docs.praison.ai/features/background-tasks) |
| Policy Engine | [Example](examples/policy/basic_policy.py) | [📖](https://docs.praison.ai/features/policy-engine) |
| Thinking Budgets | [Example](examples/thinking/basic_thinking.py) | [📖](https://docs.praison.ai/features/thinking-budgets) |
| Output Styles | [Example](examples/output/basic_output.py) | [📖](https://docs.praison.ai/features/output-styles) |
| Context Compaction | [Example](examples/compaction/basic_compaction.py) | [📖](https://docs.praison.ai/features/context-compaction) |
</details>
<details>
<summary><strong>📊 Monitoring & Management</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Sessions Management | [Example](examples/python/sessions/comprehensive-session-management.py) | [📖](https://docs.praison.ai/features/sessions) |
| Auto-Save Sessions | [Example](#session-management-python) | [📖](https://docs.praison.ai/docs/cli/session) |
| History in Context | [Example](#session-management-python) | [📖](https://docs.praison.ai/docs/cli/session) |
| Telemetry | [Example](examples/python/telemetry/production-telemetry-example.py) | [📖](https://docs.praison.ai/features/telemetry) |
| Project Docs (.praison/docs/) | [Example](#docs-cli) | [📖](https://docs.praison.ai/docs/cli/docs) |
| AI Commit Messages | [Example](#ai-commit-cli) | [📖](https://docs.praison.ai/docs/cli/commit) |
| @Mentions in Prompts | [Example](#mentions-in-prompts) | [📖](https://docs.praison.ai/docs/cli/mentions) |
</details>
<details>
<summary><strong>🖥️ CLI Features</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Slash Commands | [Example](examples/python/cli/slash_commands_example.py) | [📖](https://docs.praison.ai/docs/cli/slash-commands) |
| Autonomy Modes | [Example](examples/python/cli/autonomy_modes_example.py) | [📖](https://docs.praison.ai/docs/cli/autonomy-modes) |
| Cost Tracking | [Example](examples/python/cli/cost_tracking_example.py) | [📖](https://docs.praison.ai/docs/cli/cost-tracking) |
| Repository Map | [Example](examples/python/cli/repo_map_example.py) | [📖](https://docs.praison.ai/docs/cli/repo-map) |
| Interactive TUI | [Example](examples/python/cli/interactive_tui_example.py) | [📖](https://docs.praison.ai/docs/cli/interactive-tui) |
| Git Integration | [Example](examples/python/cli/git_integration_example.py) | [📖](https://docs.praison.ai/docs/cli/git-integration) |
| Sandbox Execution | [Example](examples/python/cli/sandbox_execution_example.py) | [📖](https://docs.praison.ai/docs/cli/sandbox-execution) |
| CLI Compare | [Example](examples/compare/cli_compare_basic.py) | [📖](https://docs.praison.ai/docs/cli/compare) |
| Profile/Benchmark | [Example](#profile-benchmark) | [📖](https://docs.praison.ai/docs/cli/profile) |
| Auto Mode | [Example](#auto-mode) | [📖](https://docs.praison.ai/docs/cli/auto) |
| Init | [Example](#init) | [📖](https://docs.praison.ai/docs/cli/init) |
| File Input | [Example](#file-input) | [📖](https://docs.praison.ai/docs/cli/file-input) |
| Final Agent | [Example](#final-agent) | [📖](https://docs.praison.ai/docs/cli/final-agent) |
| Max Tokens | [Example](#max-tokens) | [📖](https://docs.praison.ai/docs/cli/max-tokens) |
</details>
<details>
<summary><strong>🧪 Evaluation</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Accuracy Evaluation | [Example](examples/eval/accuracy_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| Performance Evaluation | [Example](examples/eval/performance_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| Reliability Evaluation | [Example](examples/eval/reliability_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
| Criteria Evaluation | [Example](examples/eval/criteria_example.py) | [📖](https://docs.praison.ai/docs/cli/eval) |
</details>
<details>
<summary><strong>🎯 Agent Skills</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Skills Management | [Example](examples/skills/basic_skill_usage.py) | [📖](https://docs.praison.ai/features/skills) |
| Custom Skills | [Example](examples/skills/custom_skill_example.py) | [📖](https://docs.praison.ai/features/skills) |
</details>
<details>
<summary><strong>⏰ 24/7 Scheduling</strong></summary>
| Feature | Code | Docs |
|---------|:----:|:----:|
| Agent Scheduler | [Example](examples/python/scheduled_agents/news_checker_live.py) | [📖](https://docs.praison.ai/docs/cli/scheduler) |
</details>
---
@@ -543,7 +745,7 @@ memory.handle_command("/memory save my_session")
| `memory="sqlite"` | Built-in | SQLite with indexing |
| `memory="chromadb"` | chromadb | Vector/semantic search |
### 6. Rules & Instructions
### 7. Rules & Instructions
PraisonAI auto-discovers instruction files from your project root and git root:
@@ -592,7 +794,7 @@ activation: always # always, glob, manual, ai_decision
- Follow PEP 8
```
### 7. Auto-Generated Memories
### 8. Auto-Generated Memories
```python
from praisonaiagents.memory import FileMemory, AutoMemory
@@ -607,7 +809,7 @@ memories = auto.process_interaction(
# Extracts: name="John", preference="Python for backend"
```
### 8. Agentic Workflows
### 9. Agentic Workflows
Create powerful multi-agent workflows with the `Workflow` class:
@@ -877,7 +1079,7 @@ callbacks:
on_workflow_complete: log_complete
```
### 9. Hooks
### 10. Hooks
Intercept and modify agent behavior at various lifecycle points:
@@ -916,7 +1118,7 @@ praisonai hooks validate hooks.json # Validate configuration
```
### 10. Shadow Git Checkpoints
### 11. Shadow Git Checkpoints
File-level undo/restore using shadow git:
@@ -953,7 +1155,7 @@ praisonai checkpoint restore abc123 # Restore to checkpoint
---
### 11. Background Tasks
### 12. Background Tasks
Run agent tasks asynchronously without blocking:
@@ -991,7 +1193,7 @@ praisonai background clear # Clear completed tasks
---
### 12. Policy Engine
### 13. Policy Engine
Control what agents can and cannot do with policy-based execution:
@@ -1032,7 +1234,7 @@ praisonai policy init # Create template
---
### 13. Thinking Budgets
### 14. Thinking Budgets
Configure token budgets for extended thinking:
@@ -1065,7 +1267,7 @@ praisonai thinking stats # Show usage statistics
---
### 14. Output Styles
### 15. Output Styles
Configure how agents format their responses:
@@ -1095,7 +1297,7 @@ praisonai output set concise # Set output style
---
### 15. Context Compaction
### 16. Context Compaction
Automatically manage context window size:
@@ -1130,7 +1332,7 @@ praisonai compaction stats # Show statistics
---
### 16. Field Names Reference (A-I-G-S)
### 17. Field Names Reference (A-I-G-S)
PraisonAI accepts both old (agents.yaml) and new (workflow.yaml) field names. Use the **canonical names** for new projects:
@@ -1164,7 +1366,7 @@ steps: # Define steps (not 'tasks')
> **Note:** The parser accepts both old and new names. Run `praisonai workflow validate <file.yaml>` to see suggestions for canonical names.
### 12. Extended agents.yaml with Workflow Patterns
### 18. Extended agents.yaml with Workflow Patterns
**Feature Parity:** Both `agents.yaml` and `workflow.yaml` now support the same features:
- All workflow patterns (route, parallel, loop, repeat)
@@ -1240,7 +1442,7 @@ Run with the same simple command:
praisonai agents.yaml
```
### 12. MCP (Model Context Protocol)
### 19. MCP (Model Context Protocol)
PraisonAI supports MCP Protocol Revision 2025-11-25 with multiple transports.
@@ -1316,7 +1518,7 @@ server.run() # stdio for Claude Desktop
| Security | Origin validation, DNS rebinding prevention |
| WebSocket | Auto-reconnect with exponential backoff |
### 13. A2A (Agent2Agent Protocol)
### 20. A2A (Agent2Agent Protocol)
PraisonAI supports the [A2A Protocol](https://a2a-protocol.org) for agent-to-agent communication, enabling your agents to be discovered and collaborate with other AI agents.
@@ -1364,6 +1566,22 @@ app.include_router(a2a.get_router())
PraisonAI provides a powerful CLI for no-code automation and quick prototyping.
### CLI Quick Reference
| Category | Commands |
|----------|----------|
| **Execution** | `praisonai`, `--auto`, `--interactive`, `--chat` |
| **Research** | `research`, `--query-rewrite`, `--deep-research` |
| **Planning** | `--planning`, `--planning-tools`, `--planning-reasoning` |
| **Workflows** | `workflow run`, `workflow list`, `workflow auto` |
| **Memory** | `memory show`, `memory add`, `memory search`, `memory clear` |
| **Knowledge** | `knowledge add`, `knowledge query`, `knowledge list` |
| **Sessions** | `session list`, `session resume`, `session delete` |
| **Tools** | `tools list`, `tools info`, `tools search` |
| **MCP** | `mcp list`, `mcp create`, `mcp enable` |
| **Development** | `commit`, `docs`, `checkpoint`, `hooks` |
| **Scheduling** | `schedule start`, `schedule list`, `schedule stop` |
### Auto Mode
```bash
pip install praisonai
@@ -1776,19 +1994,23 @@ manager.delete_checkpoint("deploy-v1")
### Tools CLI:
```bash
# List all available tools
praisonai tools list
# Get info about a specific tool
praisonai tools info internet_search
# Search for tools
praisonai tools search "web"
# Show all commands
praisonai tools help
praisonai tools doctor
praisonai tools resolve shell_tool
praisonai tools discover
praisonai tools show-sources
praisonai tools show-sources --template ai-video-editor
```
| Command | Example | Docs |
|---------|---------|------|
| `tools list` | [example](examples/tools/) | [docs](https://docs.praison.ai/docs/cli/tools) |
| `tools resolve` | [example](examples/tools/example_tools_resolve.py) | [docs](https://docs.praison.ai/docs/cli/tools-resolve) |
| `tools discover` | [example](examples/tools/example_tools_discover.py) | [docs](https://docs.praison.ai/docs/cli/tools-discover) |
| `tools show-sources` | [example](examples/tools/example_tools_sources.py) | [docs](https://docs.praison.ai/docs/cli/tools-show-sources) |
### Handoff CLI:
```bash
# Enable agent-to-agent task delegation
@@ -2137,6 +2359,24 @@ agent = Agent(
| 🌐 Web Search - Real-time search | [📖](https://docs.praison.ai/docs/cli/web-search) |
| 📥 Web Fetch - URL content retrieval | [📖](https://docs.praison.ai/docs/cli/web-fetch) |
| 💾 Prompt Caching - Cost reduction | [📖](https://docs.praison.ai/docs/cli/prompt-caching) |
| 📦 Template Catalog - Browse & discover templates | [📖](https://docs.praison.ai/docs/cli/template-catalog) |
### Template Catalog CLI
| Command | Description |
|---------|-------------|
| `praisonai templates browse` | Open template catalog in browser |
| `praisonai templates browse --print` | Print catalog URL only |
| `praisonai templates validate` | Validate template YAML files |
| `praisonai templates validate --source <dir>` | Validate specific directory |
| `praisonai templates validate --strict` | Strict validation mode |
| `praisonai templates validate --json` | JSON output format |
| `praisonai templates catalog build` | Build catalog locally |
| `praisonai templates catalog build --out <dir>` | Build to specific directory |
| `praisonai templates catalog sync` | Sync template sources |
| `praisonai templates catalog sync --source <name>` | Sync specific source |
**Examples:** [examples/catalog/](examples/catalog/) | **Docs:** [Code](https://docs.praison.ai/docs/cli/template-catalog-code) | [CLI](https://docs.praison.ai/docs/cli/template-catalog)
---
@@ -3023,6 +3263,119 @@ cd src/praisonai && uv publish
---
## ❓ FAQ & Troubleshooting
<details>
<summary><strong>ModuleNotFoundError: No module named 'praisonaiagents'</strong></summary>
Install the package:
```bash
pip install praisonaiagents
```
</details>
<details>
<summary><strong>API key not found / Authentication error</strong></summary>
Ensure your API key is set:
```bash
export OPENAI_API_KEY=your_key_here
```
For other providers, see [Environment Variables](#environment-variables).
</details>
<details>
<summary><strong>How do I use a local model (Ollama)?</strong></summary>
```bash
# Start Ollama server first
ollama serve
# Set environment variable
export OPENAI_BASE_URL=http://localhost:11434/v1
```
See [Ollama Integration](#ollama-integration) for more details.
</details>
<details>
<summary><strong>How do I persist conversations to a database?</strong></summary>
Use the `db` parameter:
```python
from praisonaiagents import Agent, db
agent = Agent(
name="Assistant",
db=db(database_url="postgresql://localhost/mydb"),
session_id="my-session"
)
```
See [Persistence (Databases)](#-persistence-databases) for supported databases.
</details>
<details>
<summary><strong>How do I enable agent memory?</strong></summary>
```python
from praisonaiagents import Agent
agent = Agent(
name="Assistant",
memory=True, # Enables file-based memory (no extra deps!)
user_id="user123"
)
```
See [Agent Memory](#6-agent-memory-zero-dependencies) for more options.
</details>
<details>
<summary><strong>How do I run multiple agents together?</strong></summary>
```python
from praisonaiagents import Agent, PraisonAIAgents
agent1 = Agent(instructions="Research topics")
agent2 = Agent(instructions="Summarize findings")
agents = PraisonAIAgents(agents=[agent1, agent2])
agents.start()
```
See [Multi Agents](#2-multi-agents) for more examples.
</details>
<details>
<summary><strong>How do I use MCP tools?</strong></summary>
```python
from praisonaiagents import Agent, MCP
agent = Agent(
tools=MCP("npx @modelcontextprotocol/server-memory")
)
```
See [MCP Protocol](#19-mcp-model-context-protocol) for all transport options.
</details>
### Getting Help
- 📚 [Full Documentation](https://docs.praison.ai)
- 🐛 [Report Issues](https://github.com/MervinPraison/PraisonAI/issues)
- 💬 [Discussions](https://github.com/MervinPraison/PraisonAI/discussions)
---
<div align="center">
<p><strong>Made with ❤️ by the PraisonAI Team</strong></p>
<p>
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.5.4" \
"praisonai>=2.7.7" \
"praisonai[chat]" \
"embedchain[github,youtube]"
+1 -1
View File
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.5.4" \
"praisonai>=2.7.7" \
"praisonai[ui]" \
"praisonai[chat]" \
"praisonai[realtime]" \
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.5.4" \
"praisonai>=2.7.7" \
"praisonai[ui]" \
"praisonai[crewai]"
+53
View File
@@ -0,0 +1,53 @@
# Templates CLI
```bash
praisonai templates list
```
```bash
praisonai templates search video
```
```bash
praisonai templates info ai-video-editor
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --output edited.mp4
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --output edited.mp4 --offline
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --output edited.mp4 --strict-tools
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --tools ./my_tools.py
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --tools-dir ./tools
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --tools-source praisonai_tools.video
```
```bash
praisonai templates run ai-video-editor --input video.mp4 --no-template-tools-py
```
```bash
praisonai templates init my-project --template ai-video-editor
```
```bash
praisonai templates cache clear
```
```bash
praisonai templates cache list
```
+104
View File
@@ -0,0 +1,104 @@
# Templates Module
## Loading Templates
```python
from praisonai.templates.loader import TemplateLoader
loader = TemplateLoader()
# Load from local path
template = loader.load("./my-template")
# Load from URI
template = loader.load("ai-video-editor")
# Load offline
template = loader.load("ai-video-editor", offline=True)
# Check requirements
missing = loader.check_requirements(template)
```
## Template Discovery
```python
from praisonai.templates.discovery import TemplateDiscovery
discovery = TemplateDiscovery(
include_package=True,
include_defaults=True,
)
# Find template
result = discovery.find_template("ai-video-editor")
# List all templates
templates = discovery.list_templates()
```
## Template Config
```python
from praisonai.templates.loader import TemplateConfig
# Access template properties
template.name
template.description
template.version
template.author
template.requires
template.workflow_file
template.agents_file
template.path
```
## Tool Override Integration
```python
from praisonai.templates.tool_override import (
create_tool_registry_with_overrides,
resolve_tools,
)
# Build registry with template sources
tools_sources = template.requires.get("tools_sources", [])
registry = create_tool_registry_with_overrides(
tools_sources=tools_sources,
template_dir=str(template.path),
include_defaults=True,
)
# Resolve tool names
tools = resolve_tools(["shell_tool"], registry=registry)
```
## TEMPLATE.yaml Schema
```yaml
name: my-template
version: "1.0.0"
description: Template description
requires:
tools: [shell_tool]
packages: [praisonai-tools]
env: [OPENAI_API_KEY]
tools_sources:
- praisonai_tools.video
- ./local_tools.py
workflow: workflow.yaml
agents: agents.yaml
config:
input:
type: string
required: true
output:
type: string
defaults:
preset: podcast
```
+65
View File
@@ -0,0 +1,65 @@
# Tools CLI
```bash
praisonai tools list
```
```bash
praisonai tools info shell_tool
```
```bash
praisonai tools info internet_search
```
```bash
praisonai tools search "web"
```
```bash
praisonai tools search "file"
```
```bash
praisonai tools doctor
```
```bash
praisonai tools doctor --json
```
```bash
praisonai tools resolve shell_tool
```
```bash
praisonai tools resolve internet_search --template ai-video-editor
```
```bash
praisonai tools resolve my_tool --tools ./my_tools.py
```
```bash
praisonai tools resolve my_tool --tools-dir ./tools
```
```bash
praisonai tools discover
```
```bash
praisonai tools discover --include praisonai_tools.video
```
```bash
praisonai tools discover --entrypoints
```
```bash
praisonai tools show-sources
```
```bash
praisonai tools show-sources --template ai-video-editor
```
+90
View File
@@ -0,0 +1,90 @@
# Tools Module
## Tool Registry
```python
from praisonai.templates.tool_override import (
create_tool_registry_with_overrides,
resolve_tools,
)
# Create registry with defaults
registry = create_tool_registry_with_overrides(include_defaults=True)
# Create registry with overrides
registry = create_tool_registry_with_overrides(
override_files=["my_tools.py"],
override_dirs=["./tools"],
include_defaults=True,
)
# Create registry with tools_sources
registry = create_tool_registry_with_overrides(
tools_sources=["praisonai_tools.video"],
template_dir="./my-template",
include_defaults=True,
)
# Resolve tool names to callables
tools = resolve_tools(
["shell_tool", "internet_search"],
registry=registry,
)
```
## Tool Override Loader
```python
from praisonai.templates.tool_override import ToolOverrideLoader
loader = ToolOverrideLoader()
# Load from file
tools = loader.load_from_file("my_tools.py")
# Load from directory
tools = loader.load_from_directory("./tools")
# Load from module
tools = loader.load_from_module("praisonai_tools.video")
# Get default tool directories
dirs = loader.get_default_tool_dirs()
```
## Resolution Order
1. CLI `--tools` files (highest priority)
2. CLI `--tools-dir` directories
3. Template `tools_sources` (from TEMPLATE.yaml)
4. Template-local `tools.py`
5. Default dirs (`~/.praison/tools`, `~/.config/praison/tools`)
6. Package discovery (`praisonai_tools`)
7. Built-in tools (lowest priority)
## Creating Custom Tools
```python
from praisonai_tools import tool
@tool
def my_custom_tool(query: str) -> str:
"""My custom tool description.
Args:
query: The search query
"""
return f"Result for: {query}"
```
## Template tools_sources
```yaml
# TEMPLATE.yaml
requires:
tools: [shell_tool]
tools_sources:
- praisonai_tools.video
- ./local_tools.py
- ./tools_dir/
```
+18
View File
@@ -14,6 +14,7 @@ examples/
│ ├── memory/ # Memory and sessions
│ ├── code/ # Code editing and external CLI tools
│ └── ...
├── serve/ # Server and endpoints examples
├── yaml/ # YAML workflow examples
└── cookbooks/ # Complete use-case examples
```
@@ -30,6 +31,23 @@ examples/
| **Tools** | [python/tools/](python/tools/) | [📖](https://docs.praison.ai/tools) |
| **Code** | [python/code/](python/code/) | [📖](https://docs.praison.ai/code) |
| **YAML** | [yaml/](yaml/) | [📖](https://docs.praison.ai/features/yaml-workflows) |
| **Doctor** | [doctor/](doctor/) | [📖](https://docs.praison.ai/cli/doctor) |
| **Serve** | [serve/](serve/) | [📖](https://docs.praison.ai/cli/serve) |
| **Endpoints** | [serve/](serve/) | [📖](https://docs.praison.ai/cli/endpoints) |
## Serve Examples
| Example | Description | CLI Command |
|---------|-------------|-------------|
| [unified_server.py](serve/unified_server.py) | All providers in one server | `praisonai serve unified` |
| [agent_as_api_single.py](serve/agent_as_api_single.py) | Single agent HTTP API | `praisonai serve agents` |
| [agents_as_api_router.py](serve/agents_as_api_router.py) | Multi-agent router API | `praisonai serve agents` |
| [a2a_server_client.py](serve/a2a_server_client.py) | A2A protocol server | `praisonai serve a2a` |
| [a2u_events_stream.py](serve/a2u_events_stream.py) | A2U event stream | `praisonai serve a2u` |
| [mcp_http_server.py](serve/mcp_http_server.py) | MCP HTTP server | `praisonai serve mcp` |
| [tools_as_mcp_server.py](serve/tools_as_mcp_server.py) | Tools as MCP server | `praisonai serve tools` |
| [agent_launch_modes.py](serve/agent_launch_modes.py) | Agent.launch() API | Python only |
| [endpoints_unified_client.py](serve/endpoints_unified_client.py) | Unified client | `praisonai endpoints` |
## Running Examples
@@ -0,0 +1,24 @@
"""
Assistants Capabilities Example
Demonstrates OpenAI Assistants API using PraisonAI capabilities.
"""
from praisonai.capabilities import assistant_list
print("=== List Assistants ===")
try:
assistants = assistant_list()
print(f"Assistants found: {len(assistants)}")
for a in assistants[:5]: # Show first 5
print(f" - {a.get('name', 'unnamed')}: {a.get('id', 'unknown')}")
except Exception as e:
print(f"Note: {e}")
print("\n=== Assistant Operations ===")
print("Available functions:")
print(" assistant_create(name, instructions, model='gpt-4o-mini')")
print(" assistant_list()")
print("\nSee CLI: praisonai assistants list")
print("See CLI: praisonai assistants create --name 'My Assistant'")
+24
View File
@@ -0,0 +1,24 @@
"""
Audio Capabilities Example
Demonstrates transcription and text-to-speech using PraisonAI capabilities.
"""
from praisonai.capabilities import transcribe, speech
# Note: Audio transcription requires an audio file
# This example shows the API structure
print("=== Audio Transcription ===")
print("To transcribe audio, use:")
print(" result = transcribe('audio.mp3', model='whisper-1')")
print(" print(result.text)")
print("\n=== Text-to-Speech ===")
print("To generate speech, use:")
print(" audio_data = speech('Hello world', model='tts-1', voice='alloy')")
print(" # Save to file or play")
print("\nNote: These operations require audio files or generate audio output.")
print("See CLI: praisonai audio transcribe <file>")
print("See CLI: praisonai audio speech <text>")
+27
View File
@@ -0,0 +1,27 @@
"""
Batches Capabilities Example
Demonstrates batch processing using PraisonAI capabilities.
"""
from praisonai.capabilities import batch_list
print("=== Batch List ===")
try:
batches = batch_list()
print(f"Batches found: {len(batches)}")
for b in batches[:5]: # Show first 5
print(f" - {b.get('id', 'unknown')}: {b.get('status', 'unknown')}")
except Exception as e:
print(f"Note: {e}")
print("Batch operations require batch jobs to be created first.")
print("\n=== Batch Operations ===")
print("Available functions:")
print(" batch_create(input_file_id, endpoint, completion_window='24h')")
print(" batch_list()")
print(" batch_retrieve(batch_id)")
print(" batch_cancel(batch_id)")
print("\nSee CLI: praisonai batches list")
print("See CLI: praisonai batches create <input_file_id>")
@@ -0,0 +1,30 @@
"""
Completions Capability Example
Demonstrates chat and text completions using PraisonAI capabilities.
"""
from praisonai.capabilities import chat_completion, text_completion
# Chat completion example
print("=== Chat Completion ===")
result = chat_completion(
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is 2 + 2? Answer in one word."}
],
model="gpt-4o-mini",
max_tokens=10
)
print(f"Response: {result.content}")
print(f"Model: {result.model}")
print(f"Usage: {result.usage}")
# Text completion example (legacy)
print("\n=== Text Completion ===")
result = text_completion(
prompt="The capital of France is",
model="gpt-3.5-turbo-instruct",
max_tokens=10
)
print(f"Response: {result.content}")
@@ -0,0 +1,27 @@
"""
Embeddings Capability Example
Demonstrates text embedding generation using PraisonAI capabilities.
"""
from praisonai.capabilities import embed
# Single text embedding
print("=== Single Text Embedding ===")
result = embed(
input="Hello, world!",
model="text-embedding-3-small"
)
print(f"Embedding dimensions: {len(result.embeddings[0])}")
print(f"First 5 values: {result.embeddings[0][:5]}")
print(f"Usage: {result.usage}")
# Multiple text embeddings
print("\n=== Multiple Text Embeddings ===")
result = embed(
input=["Hello", "World", "AI"],
model="text-embedding-3-small"
)
print(f"Number of embeddings: {len(result.embeddings)}")
for i, emb in enumerate(result.embeddings):
print(f" Text {i+1}: {len(emb)} dimensions")
+28
View File
@@ -0,0 +1,28 @@
"""
Files Capabilities Example
Demonstrates file management using PraisonAI capabilities.
"""
from praisonai.capabilities import file_list
print("=== File List ===")
try:
files = file_list()
print(f"Files found: {len(files)}")
for f in files[:5]: # Show first 5
print(f" - {f.get('filename', 'unknown')}: {f.get('id', 'unknown')}")
except Exception as e:
print(f"Note: {e}")
print("File operations require files to be uploaded first.")
print("\n=== File Operations ===")
print("Available functions:")
print(" file_create(file_path, purpose='assistants')")
print(" file_list(purpose=None)")
print(" file_retrieve(file_id)")
print(" file_delete(file_id)")
print(" file_content(file_id)")
print("\nSee CLI: praisonai files list")
print("See CLI: praisonai files upload <file>")
+31
View File
@@ -0,0 +1,31 @@
"""
Images Capability Example
Demonstrates image generation using PraisonAI capabilities.
"""
from praisonai.capabilities import image_generate
# Generate an image with DALL-E 2
print("=== Image Generation (DALL-E 2) ===")
result = image_generate(
prompt="A simple blue circle on a white background",
model="dall-e-2",
size="256x256",
n=1
)
print(f"Images generated: {len(result)}")
if result:
print(f"URL: {result[0].url[:80]}...")
# Generate with DALL-E 3 (higher quality)
print("\n=== Image Generation (DALL-E 3) ===")
result = image_generate(
prompt="A serene mountain landscape at sunset",
model="dall-e-3",
size="1024x1024",
quality="standard"
)
print(f"Images generated: {len(result)}")
if result:
print(f"Revised prompt: {result[0].revised_prompt[:80]}..." if result[0].revised_prompt else "No revised prompt")
+33
View File
@@ -0,0 +1,33 @@
"""
Messages Capability Example
Demonstrates Anthropic-style messages API and token counting.
"""
from praisonai.capabilities import messages_create, count_tokens
# Create a message (Anthropic-style)
print("=== Messages Create ===")
result = messages_create(
messages=[{"role": "user", "content": "What is the meaning of life? Answer briefly."}],
model="gpt-4o-mini", # Works with any model via LiteLLM
max_tokens=100,
system="You are a philosophical assistant."
)
print(f"Message ID: {result.id}")
if result.content:
for block in result.content:
if block.get("type") == "text":
print(f"Response: {block.get('text')}")
print(f"Usage: {result.usage}")
# Count tokens
print("\n=== Token Counting ===")
result = count_tokens(
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello, how are you today?"}
],
model="gpt-4o-mini"
)
print(f"Token count: {result.input_tokens}")
@@ -0,0 +1,24 @@
"""
Moderations Capability Example
Demonstrates content moderation using PraisonAI capabilities.
"""
from praisonai.capabilities import moderate
# Check safe content
print("=== Safe Content Check ===")
result = moderate(
input="Hello, how are you today?"
)
print(f"Flagged: {result[0].flagged}")
print(f"Categories: {list(result[0].categories.keys())[:5]}...")
# Check multiple texts
print("\n=== Multiple Text Moderation ===")
result = moderate(
input=["Hello world", "Have a nice day", "This is a test"]
)
print(f"Number of results: {len(result)}")
for i, r in enumerate(result):
print(f" Text {i+1}: Flagged = {r.flagged}")
+23
View File
@@ -0,0 +1,23 @@
"""
Realtime Capability Example
Demonstrates realtime session creation for audio/video streaming.
"""
from praisonai.capabilities import realtime_connect
# Create a realtime session
print("=== Realtime Session ===")
session = realtime_connect(
model="gpt-4o-realtime-preview",
modalities=["text", "audio"],
voice="alloy"
)
print(f"Session ID: {session.id}")
print(f"Status: {session.status}")
print(f"URL: {session.url}")
print(f"Modalities: {session.metadata.get('modalities')}")
print(f"Voice: {session.metadata.get('voice')}")
print("\nNote: To use this session, connect via WebSocket to the URL above.")
print("See OpenAI Realtime API documentation for WebSocket protocol details.")
+32
View File
@@ -0,0 +1,32 @@
"""
Rerank Capabilities Example
Demonstrates document reranking using PraisonAI capabilities.
"""
from praisonai.capabilities import rerank
print("=== Document Reranking ===")
try:
documents = [
"Python is a programming language",
"Machine learning uses algorithms",
"Python is great for data science",
"JavaScript runs in browsers"
]
results = rerank(
query="Python programming",
documents=documents,
model="cohere/rerank-english-v3.0"
)
print(f"Query: 'Python programming'")
print(f"Reranked results:")
for r in results:
print(f" Score {r.get('relevance_score', 0):.4f}: {r.get('document', {}).get('text', '')[:50]}")
except Exception as e:
print(f"Note: Reranking requires Cohere API key")
print(f"Error: {e}")
print("\nSee CLI: praisonai rerank <query> --documents 'doc1' 'doc2'")
@@ -0,0 +1,22 @@
"""
Vector Stores Capabilities Example
Demonstrates vector store management using PraisonAI capabilities.
"""
from praisonai.capabilities import vector_store_create, vector_store_search
print("=== Vector Store Operations ===")
print("Available functions:")
print(" vector_store_create(name)")
print(" vector_store_search(vector_store_id, query)")
print("\n=== Create Vector Store ===")
try:
store = vector_store_create(name="test-store")
print(f"Created: {store}")
except Exception as e:
print(f"Note: {e}")
print("\nSee CLI: praisonai vector-stores create --name 'my-store'")
print("See CLI: praisonai vector-stores search <store_id> <query>")
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
"""
Example: Fetch and search PraisonAI templates from the catalog.
This example demonstrates how to:
- Fetch templates.json from the deployed catalog
- Search templates by keyword
- Filter by tags and requirements
- Generate CLI commands
"""
import json
import urllib.request
from typing import List, Dict, Any, Optional
CATALOG_URL = "https://mervinpraison.github.io/praisonai-template-catalog/data/templates.json"
def fetch_catalog(url: str = CATALOG_URL) -> Dict[str, Any]:
"""Fetch the template catalog from URL."""
try:
with urllib.request.urlopen(url, timeout=10) as response:
return json.loads(response.read().decode())
except Exception as e:
print(f"Failed to fetch catalog: {e}")
# Return empty catalog on failure
return {"version": "0.0.0", "count": 0, "templates": []}
def search_templates(templates: List[Dict], query: str) -> List[Dict]:
"""Search templates by name, description, or tags."""
query = query.lower()
results = []
for t in templates:
if (query in t.get("name", "").lower() or
query in t.get("description", "").lower() or
any(query in tag.lower() for tag in t.get("tags", []))):
results.append(t)
return results
def filter_by_tags(templates: List[Dict], tags: List[str]) -> List[Dict]:
"""Filter templates that have all specified tags."""
return [
t for t in templates
if all(tag in t.get("tags", []) for tag in tags)
]
def filter_by_tool(templates: List[Dict], tool_name: str) -> List[Dict]:
"""Filter templates that require a specific tool."""
return [
t for t in templates
if tool_name in t.get("requires", {}).get("tools", [])
]
def get_template(templates: List[Dict], name: str) -> Optional[Dict]:
"""Get a template by name."""
for t in templates:
if t.get("name") == name:
return t
return None
def generate_cli_command(template: Dict, action: str = "run") -> str:
"""Generate CLI command for a template."""
name = template.get("name", "unknown")
if action == "run":
return f"praisonai templates run {name}"
elif action == "info":
return f"praisonai templates info {name}"
elif action == "init":
return f"praisonai templates init my-project --template {name}"
return f"praisonai templates {action} {name}"
def print_template_summary(template: Dict):
"""Print a summary of a template."""
print(f"\n{'='*60}")
print(f"Name: {template.get('name')}")
print(f"Version: {template.get('version')}")
print(f"Description: {template.get('description', '')[:100]}...")
print(f"Tags: {', '.join(template.get('tags', []))}")
requires = template.get("requires", {})
if requires.get("tools"):
print(f"Tools: {', '.join(requires['tools'])}")
if requires.get("packages"):
print(f"Packages: {', '.join(requires['packages'])}")
if requires.get("env"):
print(f"Env vars: {', '.join(requires['env'])}")
print(f"\nRun: {generate_cli_command(template, 'run')}")
print(f"{'='*60}")
def main():
print("PraisonAI Template Catalog - Python Example")
print("-" * 45)
# Fetch catalog
print("\n1. Fetching template catalog...")
catalog = fetch_catalog()
templates = catalog.get("templates", [])
print(f" Catalog version: {catalog.get('version', 'unknown')}")
print(f" Total templates: {len(templates)}")
if not templates:
print(" No templates found. The catalog may not be deployed yet.")
print(" Try building locally: praisonai templates catalog build")
return
# List all templates
print("\n2. Available templates:")
for t in templates:
print(f" - {t.get('name')} (v{t.get('version')})")
# Search for video templates
print("\n3. Searching for 'video' templates...")
video_templates = search_templates(templates, "video")
print(f" Found {len(video_templates)} video templates:")
for t in video_templates:
print(f" - {t.get('name')}: {t.get('description', '')[:50]}...")
# Filter by tool
print("\n4. Templates using 'shell_tool':")
shell_templates = filter_by_tool(templates, "shell_tool")
for t in shell_templates:
print(f" - {t.get('name')}")
# Get specific template details
if templates:
first_template = templates[0]
print(f"\n5. Template details for '{first_template.get('name')}':")
print_template_summary(first_template)
# Generate CLI commands
print("\n6. CLI commands for all templates:")
for t in templates[:5]: # First 5 only
print(f" {generate_cli_command(t, 'run')}")
print("\nDone!")
if __name__ == "__main__":
main()
+167
View File
@@ -0,0 +1,167 @@
#!/usr/bin/env npx ts-node
/**
* Example: Fetch and search PraisonAI templates from the catalog.
*
* This TypeScript example demonstrates how to:
* - Fetch templates.json from the deployed catalog
* - Search templates by keyword
* - Filter by tags and requirements
* - Generate CLI commands
*/
const CATALOG_URL = "https://mervinpraison.github.io/praisonai-template-catalog/data/templates.json";
interface Template {
name: string;
version: string;
description: string;
author?: string;
license?: string;
tags?: string[];
category?: string;
difficulty?: "beginner" | "intermediate" | "advanced";
requires?: {
tools?: string[];
packages?: string[];
env?: string[];
};
}
interface Catalog {
version: string;
generated_at: string;
count: number;
templates: Template[];
}
async function fetchCatalog(url: string = CATALOG_URL): Promise<Catalog> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch catalog: ${response.statusText}`);
}
return response.json();
}
function searchTemplates(templates: Template[], query: string): Template[] {
const q = query.toLowerCase();
return templates.filter(t =>
t.name.toLowerCase().includes(q) ||
t.description?.toLowerCase().includes(q) ||
t.tags?.some(tag => tag.toLowerCase().includes(q))
);
}
function filterByTags(templates: Template[], tags: string[]): Template[] {
return templates.filter(t =>
tags.every(tag => t.tags?.includes(tag))
);
}
function filterByTool(templates: Template[], toolName: string): Template[] {
return templates.filter(t =>
t.requires?.tools?.includes(toolName)
);
}
function getTemplate(templates: Template[], name: string): Template | undefined {
return templates.find(t => t.name === name);
}
function generateCLICommand(template: Template, action: string = "run"): string {
const name = template.name;
switch (action) {
case "run":
return `praisonai templates run ${name}`;
case "info":
return `praisonai templates info ${name}`;
case "init":
return `praisonai templates init my-project --template ${name}`;
default:
return `praisonai templates ${action} ${name}`;
}
}
function printTemplateSummary(template: Template): void {
console.log("\n" + "=".repeat(60));
console.log(`Name: ${template.name}`);
console.log(`Version: ${template.version}`);
console.log(`Description: ${template.description?.slice(0, 100)}...`);
console.log(`Tags: ${template.tags?.join(", ") || "none"}`);
const requires = template.requires;
if (requires?.tools?.length) {
console.log(`Tools: ${requires.tools.join(", ")}`);
}
if (requires?.packages?.length) {
console.log(`Packages: ${requires.packages.join(", ")}`);
}
if (requires?.env?.length) {
console.log(`Env vars: ${requires.env.join(", ")}`);
}
console.log(`\nRun: ${generateCLICommand(template, "run")}`);
console.log("=".repeat(60));
}
async function main(): Promise<void> {
console.log("PraisonAI Template Catalog - TypeScript Example");
console.log("-".repeat(45));
// Fetch catalog
console.log("\n1. Fetching template catalog...");
let catalog: Catalog;
try {
catalog = await fetchCatalog();
} catch (error) {
console.log(` Failed to fetch: ${error}`);
console.log(" The catalog may not be deployed yet.");
return;
}
const templates = catalog.templates;
console.log(` Catalog version: ${catalog.version}`);
console.log(` Total templates: ${templates.length}`);
if (templates.length === 0) {
console.log(" No templates found.");
return;
}
// List all templates
console.log("\n2. Available templates:");
templates.forEach(t => {
console.log(` - ${t.name} (v${t.version})`);
});
// Search for video templates
console.log("\n3. Searching for 'video' templates...");
const videoTemplates = searchTemplates(templates, "video");
console.log(` Found ${videoTemplates.length} video templates:`);
videoTemplates.forEach(t => {
console.log(` - ${t.name}: ${t.description?.slice(0, 50)}...`);
});
// Filter by tool
console.log("\n4. Templates using 'shell_tool':");
const shellTemplates = filterByTool(templates, "shell_tool");
shellTemplates.forEach(t => {
console.log(` - ${t.name}`);
});
// Get specific template details
if (templates.length > 0) {
const firstTemplate = templates[0];
console.log(`\n5. Template details for '${firstTemplate.name}':`);
printTemplateSummary(firstTemplate);
}
// Generate CLI commands
console.log("\n6. CLI commands for all templates:");
templates.slice(0, 5).forEach(t => {
console.log(` ${generateCLICommand(t, "run")}`);
});
console.log("\nDone!");
}
main().catch(console.error);
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""
Run all catalog examples and report pass/fail status.
Usage:
python run_all_catalog_examples.py
Environment variables:
OPENAI_API_KEY or PRAISONAI_OPENAI_API_KEY - Required for agent example
PRAISONAI_RUN_INTEGRATION - Set to "1" to run integration tests
"""
import os
import subprocess
import sys
from pathlib import Path
SCRIPT_DIR = Path(__file__).parent
def run_example(name: str, script: str, requires_api_key: bool = False) -> bool:
"""Run an example script and return success status."""
print(f"\n{'='*60}")
print(f"Running: {name}")
print(f"Script: {script}")
print("="*60)
# Check API key requirement
if requires_api_key:
api_key = os.environ.get("OPENAI_API_KEY") or os.environ.get("PRAISONAI_OPENAI_API_KEY")
run_integration = os.environ.get("PRAISONAI_RUN_INTEGRATION") == "1"
if not api_key:
print(f"⏭️ SKIPPED: {name} (no API key)")
print(" Set OPENAI_API_KEY to run this example")
return True # Not a failure, just skipped
if not run_integration:
print(f"⏭️ SKIPPED: {name} (integration tests disabled)")
print(" Set PRAISONAI_RUN_INTEGRATION=1 to run")
return True
script_path = SCRIPT_DIR / script
if not script_path.exists():
print(f"❌ FAILED: Script not found: {script_path}")
return False
try:
result = subprocess.run(
[sys.executable, str(script_path)],
capture_output=True,
text=True,
timeout=60,
cwd=str(SCRIPT_DIR)
)
print(result.stdout)
if result.stderr:
print(f"STDERR: {result.stderr}")
if result.returncode == 0:
print(f"✅ PASSED: {name}")
return True
else:
print(f"❌ FAILED: {name} (exit code {result.returncode})")
return False
except subprocess.TimeoutExpired:
print(f"❌ FAILED: {name} (timeout)")
return False
except Exception as e:
print(f"❌ FAILED: {name} ({e})")
return False
def main():
print("PraisonAI Template Catalog - Example Runner")
print("=" * 50)
# Check environment
api_key = os.environ.get("OPENAI_API_KEY") or os.environ.get("PRAISONAI_OPENAI_API_KEY")
if api_key:
print(f"API key: present (...{api_key[-4:]})")
else:
print("API key: not set")
run_integration = os.environ.get("PRAISONAI_RUN_INTEGRATION") == "1"
print(f"Integration tests: {'enabled' if run_integration else 'disabled'}")
# Define examples
examples = [
("Fetch Templates (Python)", "fetch_templates.py", False),
("Template Finder Agent", "template_finder_agent.py", True),
]
# Run examples
results = []
for name, script, requires_key in examples:
success = run_example(name, script, requires_key)
results.append((name, success))
# Summary
print("\n" + "=" * 60)
print("SUMMARY")
print("=" * 60)
passed = sum(1 for _, s in results if s)
failed = sum(1 for _, s in results if not s)
for name, success in results:
status = "✅ PASS" if success else "❌ FAIL"
print(f" {status}: {name}")
print(f"\nTotal: {passed} passed, {failed} failed")
# Exit with appropriate code
sys.exit(0 if failed == 0 else 1)
if __name__ == "__main__":
main()
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env python3
"""
Example: Template Finder Agent
An Agent()-centric example that uses an AI agent to find templates
based on natural language queries.
Requires: OPENAI_API_KEY environment variable
"""
import json
import os
import urllib.request
CATALOG_URL = "https://mervinpraison.github.io/praisonai-template-catalog/data/templates.json"
def fetch_templates() -> list:
"""Fetch templates from catalog."""
try:
with urllib.request.urlopen(CATALOG_URL, timeout=10) as response:
data = json.loads(response.read().decode())
return data.get("templates", [])
except Exception:
return []
def search_templates_tool(query: str) -> str:
"""
Search templates by keyword.
Args:
query: Search query (e.g., "video editing", "transcript", "data")
Returns:
JSON string with matching templates
"""
templates = fetch_templates()
query_lower = query.lower()
results = []
for t in templates:
if (query_lower in t.get("name", "").lower() or
query_lower in t.get("description", "").lower() or
any(query_lower in tag.lower() for tag in t.get("tags", []))):
results.append({
"name": t.get("name"),
"description": t.get("description", "")[:100],
"tags": t.get("tags", []),
"cli_command": f"praisonai templates run {t.get('name')}"
})
if not results:
return json.dumps({"message": "No templates found matching your query", "templates": []})
return json.dumps({"count": len(results), "templates": results})
def list_all_templates_tool() -> str:
"""
List all available templates.
Returns:
JSON string with all template names and descriptions
"""
templates = fetch_templates()
if not templates:
return json.dumps({"message": "No templates available", "templates": []})
results = [
{"name": t.get("name"), "description": t.get("description", "")[:80]}
for t in templates
]
return json.dumps({"count": len(results), "templates": results})
def get_template_details_tool(name: str) -> str:
"""
Get detailed information about a specific template.
Args:
name: Template name (e.g., "ai-video-editor")
Returns:
JSON string with template details
"""
templates = fetch_templates()
for t in templates:
if t.get("name") == name:
return json.dumps({
"name": t.get("name"),
"version": t.get("version"),
"description": t.get("description"),
"author": t.get("author"),
"tags": t.get("tags", []),
"requires": t.get("requires", {}),
"cli_commands": {
"run": f"praisonai templates run {name}",
"info": f"praisonai templates info {name}",
"init": f"praisonai templates init my-project --template {name}"
}
})
return json.dumps({"error": f"Template '{name}' not found"})
def check_api_key() -> bool:
"""Check if API key is available."""
key = os.environ.get("OPENAI_API_KEY") or os.environ.get("PRAISONAI_OPENAI_API_KEY")
if key:
print(f"API key present: ...{key[-4:]}")
return True
return False
def main():
print("PraisonAI Template Finder Agent")
print("=" * 40)
# Check for API key
if not check_api_key():
print("\n⚠️ No API key found.")
print("Set OPENAI_API_KEY or PRAISONAI_OPENAI_API_KEY to use the agent.")
print("\nFalling back to direct tool usage:\n")
# Demo the tools directly
print("1. Listing all templates:")
result = list_all_templates_tool()
data = json.loads(result)
for t in data.get("templates", [])[:5]:
print(f" - {t['name']}: {t['description'][:50]}...")
print("\n2. Searching for 'video' templates:")
result = search_templates_tool("video")
data = json.loads(result)
for t in data.get("templates", []):
print(f" - {t['name']}")
print(f" Run: {t['cli_command']}")
return
# Import Agent only if API key is available
try:
from praisonaiagents import Agent
except ImportError:
print("praisonaiagents not installed. Install with: pip install praisonaiagents")
return
# Create the Template Finder Agent
agent = Agent(
name="Template Finder",
role="PraisonAI Template Expert",
goal="Help users find the right template for their needs",
backstory="""You are an expert on PraisonAI templates. You help users
discover templates that match their requirements. You can search templates,
list all available templates, and provide detailed information about specific
templates. Always provide the CLI command to run the template.""",
tools=[
search_templates_tool,
list_all_templates_tool,
get_template_details_tool
],
verbose=True
)
# Example queries
queries = [
"Find me a template for editing videos",
"What templates are available for working with transcripts?",
"Show me details about the ai-video-editor template"
]
print("\nRunning Template Finder Agent...")
print("-" * 40)
for query in queries:
print(f"\n📝 Query: {query}")
print("-" * 40)
try:
result = agent.start(query)
print(f"\n🤖 Response:\n{result}")
except Exception as e:
print(f"Error: {e}")
print("\n" + "=" * 40)
if __name__ == "__main__":
main()
+65
View File
@@ -0,0 +1,65 @@
# PraisonAI Doctor Examples
Examples demonstrating the PraisonAI Doctor health check and diagnostics system.
## CLI Examples
| Command | Description |
|---------|-------------|
| `praisonai doctor` | Run all fast health checks |
| `praisonai doctor --version` | Show doctor version |
| `praisonai doctor --list-checks` | List all available checks |
| `praisonai doctor env` | Check environment configuration |
| `praisonai doctor config` | Validate configuration files |
| `praisonai doctor tools` | Check tool availability |
| `praisonai doctor db` | Check database drivers |
| `praisonai doctor mcp` | Check MCP configuration |
| `praisonai doctor obs` | Check observability providers |
| `praisonai doctor skills` | Check agent skills |
| `praisonai doctor memory` | Check memory storage |
| `praisonai doctor permissions` | Check filesystem permissions |
| `praisonai doctor network` | Check network connectivity |
| `praisonai doctor performance` | Check import times |
| `praisonai doctor ci` | CI mode with JSON output |
| `praisonai doctor selftest` | Test agent functionality |
## Global Flags
| Flag | Description |
|------|-------------|
| `--json` | Output in JSON format |
| `--format text\|json` | Output format |
| `--output PATH` | Write report to file |
| `--deep` | Enable deeper probes |
| `--timeout SEC` | Per-check timeout |
| `--strict` | Treat warnings as failures |
| `--quiet` | Minimal output |
| `--no-color` | Disable colors |
| `--only IDS` | Only run these checks |
| `--skip IDS` | Skip these checks |
## Python Examples
| File | Description |
|------|-------------|
| [basic_doctor.py](basic_doctor.py) | Programmatic health checks |
| [ci_integration.py](ci_integration.py) | CI/CD pipeline integration |
## Quick Start
```bash
# Run basic health checks
praisonai doctor
# Run with JSON output
praisonai doctor --json
# Run specific checks
praisonai doctor --only python_version,openai_api_key
# CI mode
praisonai doctor ci
# Save report to file
praisonai doctor --output report.json
```
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env python3
"""
Basic Doctor Example - Programmatic health checks for PraisonAI
This example demonstrates how to use the Doctor module programmatically
to run health checks and diagnostics.
"""
import json
import sys
# Add the praisonai path for development
sys.path.insert(0, '/Users/praison/praisonai-package/src/praisonai')
from praisonai.cli.features.doctor import DoctorEngine
from praisonai.cli.features.doctor.models import DoctorConfig, CheckCategory
from praisonai.cli.features.doctor.registry import get_registry
from praisonai.cli.features.doctor.checks import register_all_checks
from praisonai.cli.features.doctor.formatters import get_formatter
def run_basic_checks():
"""Run basic health checks."""
print("=" * 60)
print("Running Basic Health Checks")
print("=" * 60)
# Register all checks
register_all_checks()
# Create config for fast checks only
config = DoctorConfig(
deep=False,
timeout=10.0,
strict=False,
quiet=False,
)
# Create and run engine
engine = DoctorEngine(config)
report = engine.run()
# Format and print results
formatter = get_formatter("text", no_color=True)
print(formatter.format_report(report))
return report.exit_code
def run_environment_checks():
"""Run only environment checks."""
print("\n" + "=" * 60)
print("Running Environment Checks Only")
print("=" * 60)
# Register all checks
register_all_checks()
config = DoctorConfig(deep=False)
engine = DoctorEngine(config)
# Run only environment category
engine.run_checks(categories=[CheckCategory.ENVIRONMENT])
report = engine.generate_report()
formatter = get_formatter("text", no_color=True)
print(formatter.format_report(report))
return report.exit_code
def run_specific_checks():
"""Run specific checks by ID."""
print("\n" + "=" * 60)
print("Running Specific Checks")
print("=" * 60)
# Register all checks
register_all_checks()
# Only run these specific checks
config = DoctorConfig(
only=["python_version", "openai_api_key", "os_info"]
)
engine = DoctorEngine(config)
report = engine.run()
formatter = get_formatter("text", no_color=True)
print(formatter.format_report(report))
return report.exit_code
def run_json_output():
"""Run checks and get JSON output."""
print("\n" + "=" * 60)
print("Running Checks with JSON Output")
print("=" * 60)
# Register all checks
register_all_checks()
config = DoctorConfig(
only=["python_version", "os_info"],
format="json"
)
engine = DoctorEngine(config)
report = engine.run()
# Get JSON output
formatter = get_formatter("json")
json_output = formatter.format_report(report)
# Parse and pretty print
data = json.loads(json_output)
print(json.dumps(data, indent=2))
return report.exit_code
def list_available_checks():
"""List all available checks."""
print("\n" + "=" * 60)
print("Available Checks")
print("=" * 60)
# Register all checks
register_all_checks()
registry = get_registry()
checks = registry.get_all_checks()
# Sort by category
checks.sort(key=lambda c: c.category.value)
current_category = None
for check in checks:
if check.category != current_category:
current_category = check.category
print(f"\n {current_category.value.upper()}:")
deep_marker = " [deep]" if check.requires_deep else ""
print(f" {check.id:30} {check.description}{deep_marker}")
if __name__ == "__main__":
print("PraisonAI Doctor - Programmatic Usage Examples\n")
# List available checks
list_available_checks()
# Run basic checks
exit_code = run_basic_checks()
print(f"\nBasic checks exit code: {exit_code}")
# Run environment checks only
exit_code = run_environment_checks()
print(f"\nEnvironment checks exit code: {exit_code}")
# Run specific checks
exit_code = run_specific_checks()
print(f"\nSpecific checks exit code: {exit_code}")
# Run with JSON output
exit_code = run_json_output()
print(f"\nJSON output exit code: {exit_code}")
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env python3
"""
CI Integration Example - Using Doctor in CI/CD pipelines
This example demonstrates how to integrate PraisonAI Doctor
into CI/CD pipelines for automated health checks.
"""
import json
import subprocess
import sys
def run_doctor_ci():
"""Run doctor in CI mode and parse results."""
print("Running PraisonAI Doctor in CI mode...")
result = subprocess.run(
[sys.executable, "-m", "praisonai", "doctor", "ci"],
capture_output=True,
text=True,
timeout=120
)
# Parse JSON output
try:
report = json.loads(result.stdout)
except json.JSONDecodeError:
print("Error: Could not parse doctor output")
print(result.stdout)
print(result.stderr)
return 1
# Print summary
summary = report.get("summary", {})
print("\nDoctor CI Results:")
print(f" Total checks: {summary.get('total', 0)}")
print(f" Passed: {summary.get('passed', 0)}")
print(f" Warnings: {summary.get('warnings', 0)}")
print(f" Failed: {summary.get('failed', 0)}")
print(f" Skipped: {summary.get('skipped', 0)}")
print(f" Errors: {summary.get('errors', 0)}")
print(f"\nExit code: {report.get('exit_code', -1)}")
# Check for failures
if summary.get('failed', 0) > 0:
print("\nFailed checks:")
for check in report.get("results", []):
if check.get("status") == "fail":
print(f" - {check.get('title')}: {check.get('message')}")
if check.get("remediation"):
print(f" Fix: {check.get('remediation')}")
return result.returncode
def run_specific_checks_ci():
"""Run specific checks for CI."""
print("\nRunning specific checks for CI...")
# Only run critical checks
critical_checks = [
"python_version",
"praisonai_package",
"openai_api_key",
]
result = subprocess.run(
[
sys.executable, "-m", "praisonai", "doctor",
"--json",
"--only", ",".join(critical_checks)
],
capture_output=True,
text=True,
timeout=60
)
try:
report = json.loads(result.stdout)
print(f"Critical checks: {report['summary']['passed']}/{report['summary']['total']} passed")
return result.returncode
except json.JSONDecodeError:
print("Error parsing output")
return 1
def save_report_to_file():
"""Save doctor report to a file for artifact upload."""
print("\nSaving doctor report to file...")
result = subprocess.run(
[
sys.executable, "-m", "praisonai", "doctor",
"--json",
"--output", "/tmp/doctor-report.json"
],
capture_output=True,
text=True,
timeout=120
)
if result.returncode in [0, 1]:
print("Report saved to /tmp/doctor-report.json")
# Read and display summary
with open("/tmp/doctor-report.json", "r") as f:
report = json.load(f)
print(f"Summary: {report['summary']}")
return result.returncode
if __name__ == "__main__":
print("PraisonAI Doctor - CI Integration Examples\n")
print("=" * 60)
# Run CI mode
exit_code = run_doctor_ci()
# Run specific checks
run_specific_checks_ci()
# Save report
save_report_to_file()
print(f"\nFinal exit code: {exit_code}")
sys.exit(exit_code)
+174
View File
@@ -0,0 +1,174 @@
#!/usr/bin/env python3
"""
PraisonAI Endpoints Example
This example demonstrates how to:
1. Start the recipe server
2. Use the endpoints CLI to interact with it
3. Invoke recipes via HTTP
Prerequisites:
- pip install praisonai[serve]
- Set OPENAI_API_KEY environment variable
Usage:
# Terminal 1: Start server
praisonai recipe serve --port 8765
# Terminal 2: Run this example
python endpoints_example.py
"""
import json
import os
import subprocess
import sys
import urllib.request
import urllib.error
# Configuration
SERVER_URL = os.environ.get("PRAISONAI_ENDPOINTS_URL", "http://localhost:8765")
def check_server_health():
"""Check if the server is running."""
try:
req = urllib.request.Request(f"{SERVER_URL}/health")
with urllib.request.urlopen(req, timeout=5) as response:
data = json.loads(response.read().decode())
return data.get("status") == "healthy"
except Exception:
return False
def list_endpoints():
"""List available endpoints using CLI."""
print("\n=== Listing Endpoints (CLI) ===")
result = subprocess.run(
["python", "-m", "praisonai.cli.main", "endpoints", "list", "--format", "json"],
capture_output=True,
text=True,
)
if result.returncode == 0:
recipes = json.loads(result.stdout)
print(f"Found {len(recipes)} endpoints:")
for r in recipes:
print(f" - {r['name']} ({r['version']}): {r.get('description', '')[:50]}")
return recipes
else:
print(f"Error: {result.stderr}")
return []
def describe_endpoint(name: str):
"""Describe an endpoint using CLI."""
print(f"\n=== Describing Endpoint: {name} ===")
result = subprocess.run(
["python", "-m", "praisonai.cli.main", "endpoints", "describe", name, "--url", SERVER_URL],
capture_output=True,
text=True,
)
if result.returncode == 0:
info = json.loads(result.stdout)
print(f"Name: {info.get('name')}")
print(f"Version: {info.get('version')}")
print(f"Description: {info.get('description')}")
return info
else:
print(f"Error: {result.stderr}")
return None
def invoke_endpoint_cli(name: str, input_data: dict):
"""Invoke an endpoint using CLI."""
print(f"\n=== Invoking Endpoint (CLI): {name} ===")
result = subprocess.run(
[
"python", "-m", "praisonai.cli.main", "endpoints", "invoke", name,
"--url", SERVER_URL,
"--input-json", json.dumps(input_data),
"--json",
"--dry-run", # Use dry-run for example
],
capture_output=True,
text=True,
)
if result.returncode == 0:
response = json.loads(result.stdout)
print(f"Run ID: {response.get('run_id')}")
print(f"Status: {response.get('status')}")
return response
else:
print(f"Error: {result.stderr}")
return None
def invoke_endpoint_http(name: str, input_data: dict):
"""Invoke an endpoint using HTTP directly."""
print(f"\n=== Invoking Endpoint (HTTP): {name} ===")
body = json.dumps({
"recipe": name,
"input": input_data,
"options": {"dry_run": True},
}).encode()
req = urllib.request.Request(
f"{SERVER_URL}/v1/recipes/run",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=30) as response:
data = json.loads(response.read().decode())
print(f"Run ID: {data.get('run_id')}")
print(f"Status: {data.get('status')}")
print(f"Output: {data.get('output')}")
return data
except urllib.error.HTTPError as e:
print(f"HTTP Error: {e.code} - {e.read().decode()}")
return None
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Endpoints Example")
print("=" * 60)
# Check if server is running
print("\n=== Checking Server Health ===")
if not check_server_health():
print(f"Server not running at {SERVER_URL}")
print("\nPlease start the server first:")
print(" praisonai recipe serve --port 8765")
sys.exit(1)
print("✓ Server is healthy")
# List endpoints
recipes = list_endpoints()
if not recipes:
print("No recipes available")
sys.exit(1)
# Use first available recipe
recipe_name = recipes[0]["name"]
# Describe endpoint
describe_endpoint(recipe_name)
# Invoke via CLI
invoke_endpoint_cli(recipe_name, {"query": "Hello from CLI"})
# Invoke via HTTP
invoke_endpoint_http(recipe_name, {"query": "Hello from HTTP"})
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+19
View File
@@ -0,0 +1,19 @@
/**
* Basic Agent Example
* Demonstrates simple agent usage with OpenAI
*/
import { Agent } from 'praisonai';
async function main() {
const agent = new Agent({
name: 'Assistant',
instructions: 'You are a helpful assistant. Be concise and informative.',
llm: 'openai/gpt-4o-mini'
});
const response = await agent.chat('What is TypeScript?');
console.log('Response:', response.text);
}
main().catch(console.error);
+47
View File
@@ -0,0 +1,47 @@
/**
* Context Agent Example
* Demonstrates RAG-enabled agent with knowledge base
*/
import { ContextAgent, createContextAgent, KnowledgeBase } from 'praisonai';
async function main() {
// Create knowledge base
const kb = new KnowledgeBase();
// Add documents
await kb.add({
id: 'doc1',
content: 'TypeScript is a strongly typed programming language that builds on JavaScript.',
metadata: { topic: 'typescript' }
});
await kb.add({
id: 'doc2',
content: 'TypeScript adds optional static typing and class-based object-oriented programming.',
metadata: { topic: 'typescript' }
});
await kb.add({
id: 'doc3',
content: 'PraisonAI is a framework for building AI agents in TypeScript and Python.',
metadata: { topic: 'praisonai' }
});
// Create context agent with knowledge base
const agent = createContextAgent({
name: 'KnowledgeAgent',
llm: 'openai/gpt-4o-mini',
knowledgeBase: kb,
maxContextDocs: 3
});
// Query with context
const response = await agent.chat('What is TypeScript?');
console.log('Response:', response.text);
// Check conversation history
console.log('\nConversation history:', agent.getHistory().length, 'messages');
}
main().catch(console.error);
+29
View File
@@ -0,0 +1,29 @@
/**
* Image Agent Example
* Demonstrates image analysis capabilities
*/
import { ImageAgent, createImageAgent } from 'praisonai';
async function main() {
const agent = createImageAgent({
name: 'VisionAgent',
llm: 'openai/gpt-4o-mini',
verbose: true
});
console.log('Image Agent created:', agent.name);
// Note: For actual image analysis, provide a real image URL
// const analysis = await agent.analyze({
// imageUrl: 'https://example.com/image.jpg',
// prompt: 'Describe this image in detail'
// });
// console.log('Analysis:', analysis);
// Chat without image
const response = await agent.chat('What types of images can you analyze?');
console.log('Response:', response);
}
main().catch(console.error);
+48
View File
@@ -0,0 +1,48 @@
/**
* Multi-Agent Example
* Demonstrates multiple agents working together
*/
import { Agent, PraisonAIAgents, Task } from 'praisonai';
async function main() {
// Create specialized agents
const researcher = new Agent({
name: 'Researcher',
role: 'Research Specialist',
goal: 'Find accurate information on topics',
instructions: 'You research topics thoroughly and provide factual information.'
});
const writer = new Agent({
name: 'Writer',
role: 'Content Writer',
goal: 'Create engaging content from research',
instructions: 'You write clear, engaging content based on provided research.'
});
// Create tasks
const researchTask = new Task({
description: 'Research the benefits of TypeScript over JavaScript',
expectedOutput: 'A list of key benefits with explanations',
agent: researcher
});
const writeTask = new Task({
description: 'Write a short article about TypeScript benefits',
expectedOutput: 'A 200-word article',
agent: writer
});
// Run agents
const agents = new PraisonAIAgents({
agents: [researcher, writer],
tasks: [researchTask, writeTask],
process: 'sequential'
});
const result = await agents.start();
console.log('Result:', result);
}
main().catch(console.error);
+33
View File
@@ -0,0 +1,33 @@
/**
* Deep Research Agent Example
* Demonstrates comprehensive research with citations
*/
import { DeepResearchAgent, createDeepResearchAgent } from 'praisonai';
async function main() {
const agent = createDeepResearchAgent({
name: 'Scholar',
llm: 'openai/gpt-4o-mini',
maxIterations: 5,
verbose: true
});
console.log('Research Agent:', agent.name);
// Conduct research
const result = await agent.research('What are the key benefits of TypeScript?');
console.log('\n=== Research Results ===');
console.log('Answer:', result.answer.substring(0, 500) + '...');
console.log('\nConfidence:', result.confidence);
console.log('Reasoning steps:', result.reasoning.length);
// Show reasoning
console.log('\n=== Reasoning Process ===');
result.reasoning.forEach(step => {
console.log(`Step ${step.step}: ${step.thought}`);
});
}
main().catch(console.error);
+57
View File
@@ -0,0 +1,57 @@
/**
* Router Agent Example
* Demonstrates routing requests to specialized agents
*/
import { RouterAgent, createRouter, routeConditions, Agent } from 'praisonai';
async function main() {
// Create specialized agents
const mathAgent = {
name: 'MathAgent',
chat: async (input: string) => ({ text: `Math answer for: ${input}` })
} as any;
const codeAgent = {
name: 'CodeAgent',
chat: async (input: string) => ({ text: `Code solution for: ${input}` })
} as any;
const generalAgent = {
name: 'GeneralAgent',
chat: async (input: string) => ({ text: `General response: ${input}` })
} as any;
// Create router with conditions
const router = createRouter({
name: 'SmartRouter',
routes: [
{
agent: mathAgent,
condition: routeConditions.keywords(['math', 'calculate', 'number', 'equation']),
priority: 10
},
{
agent: codeAgent,
condition: routeConditions.keywords(['code', 'program', 'function', 'javascript']),
priority: 10
}
],
defaultAgent: generalAgent
});
// Test routing
const queries = [
'Calculate 2 + 2',
'Write a function to sort an array',
'What is the weather today?'
];
for (const query of queries) {
const result = await router.route(query);
console.log(`Query: "${query}"`);
console.log(`Routed to: ${result?.agent.name || 'default'}\n`);
}
}
main().catch(console.error);
+59
View File
@@ -0,0 +1,59 @@
/**
* AutoAgents Example
* Demonstrates automatic agent generation from task descriptions
*/
import { AutoAgents, createAutoAgents } from 'praisonai';
async function main() {
const auto = createAutoAgents({
pattern: 'sequential',
verbose: true
});
// Analyze task complexity
console.log('=== Complexity Analysis ===');
const tasks = [
'Write a hello world function',
'Build a web scraper that extracts product data',
'Create a multi-step data pipeline with validation, transformation, and multiple output formats'
];
tasks.forEach(task => {
const complexity = auto.analyzeComplexity(task);
console.log(`"${task.substring(0, 40)}..." -> ${complexity}`);
});
// Recommend patterns
console.log('\n=== Pattern Recommendations ===');
const patternTasks = [
'Process items in parallel',
'Route requests to different handlers',
'Orchestrate multiple workers',
'Evaluate and optimize results'
];
patternTasks.forEach(task => {
const pattern = auto.recommendPattern(task);
console.log(`"${task}" -> ${pattern}`);
});
// Generate agent configuration
console.log('\n=== Generate Agent Config ===');
console.log('Generating agents for: "Build a web scraper"');
const team = await auto.generate('Build a web scraper that extracts product prices from e-commerce sites');
console.log('\nGenerated Team:');
console.log('Pattern:', team.pattern);
console.log('Agents:', team.agents.length);
team.agents.forEach(agent => {
console.log(` - ${agent.name}: ${agent.role}`);
});
console.log('Tasks:', team.tasks.length);
team.tasks.forEach(task => {
console.log(` - ${task.description.substring(0, 50)}...`);
});
}
main().catch(console.error);
+47
View File
@@ -0,0 +1,47 @@
/**
* Redis Database Example
*/
import { createMemoryRedis } from '../../../src/praisonai-ts/src';
async function main() {
// Use in-memory Redis for this example
const redis = createMemoryRedis();
await redis.connect();
console.log('Connected to Redis');
// Basic get/set
await redis.set('user:123', { name: 'John', role: 'admin' });
const user = await redis.get('user:123');
console.log('User:', user);
// Set with TTL
await redis.set('session:abc', { token: 'xyz' }, 60);
const ttl = await redis.ttl('session:abc');
console.log('Session TTL:', ttl, 'seconds');
// Hash operations
await redis.hset('profile:123', 'email', '[email protected]');
await redis.hset('profile:123', 'phone', '555-1234');
const profile = await redis.hgetall('profile:123');
console.log('Profile:', profile);
// List operations
await redis.rpush('queue:tasks', { id: 1, type: 'process' });
await redis.rpush('queue:tasks', { id: 2, type: 'notify' });
const tasks = await redis.lrange('queue:tasks', 0, -1);
console.log('Tasks:', tasks);
// Pub/Sub (memory only)
await redis.subscribe('events', (message) => {
console.log('Received event:', message);
});
await redis.publish('events', JSON.stringify({ type: 'user_joined' }));
// Cleanup
await redis.disconnect();
console.log('Done!');
}
main().catch(console.error);
+64
View File
@@ -0,0 +1,64 @@
/**
* Evaluation Framework Example
* Demonstrates accuracy, performance, and reliability evaluation
*/
import { accuracyEval, performanceEval, reliabilityEval, EvalSuite } from 'praisonai';
async function main() {
console.log('=== Accuracy Evaluation ===');
const accuracyResult = await accuracyEval({
input: 'What is 2 + 2?',
expectedOutput: '4',
actualOutput: 'The answer is 4'
});
console.log('Passed:', accuracyResult.passed);
console.log('Score:', accuracyResult.score);
console.log('Duration:', accuracyResult.duration, 'ms');
console.log('\n=== Performance Evaluation ===');
const perfResult = await performanceEval({
func: async () => {
// Simulate some work
await new Promise(r => setTimeout(r, 100));
return 'done';
},
iterations: 5,
warmupRuns: 1
});
console.log('Iterations:', perfResult.times.length);
console.log('Avg time:', perfResult.avgTime.toFixed(2), 'ms');
console.log('Min time:', perfResult.minTime.toFixed(2), 'ms');
console.log('Max time:', perfResult.maxTime.toFixed(2), 'ms');
console.log('\n=== Reliability Evaluation ===');
const reliabilityResult = await reliabilityEval({
expectedToolCalls: ['search', 'calculate'],
actualToolCalls: ['search', 'calculate']
});
console.log('Passed:', reliabilityResult.passed);
console.log('Score:', reliabilityResult.score);
console.log('\n=== Eval Suite ===');
const suite = new EvalSuite();
await suite.runAccuracy('test1', {
input: 'Hello',
expectedOutput: 'Hi',
actualOutput: 'Hi there!'
});
await suite.runAccuracy('test2', {
input: 'Goodbye',
expectedOutput: 'Bye',
actualOutput: 'Bye!'
});
const summary = suite.getSummary();
console.log('Total tests:', summary.total);
console.log('Passed:', summary.passed);
console.log('Failed:', summary.failed);
console.log('Pass rate:', (summary.passRate * 100).toFixed(1) + '%');
}
main().catch(console.error);
@@ -0,0 +1,67 @@
/**
* Content Guardrails Example
* Demonstrates input/output validation
*/
import { guardrail, GuardrailManager, builtinGuardrails, LLMGuardrail } from 'praisonai';
async function main() {
// Create custom guardrail
const noSpamGuardrail = guardrail({
name: 'no_spam',
check: (content) => {
const spamWords = ['buy now', 'free money', 'click here'];
const hasSpam = spamWords.some(word =>
content.toLowerCase().includes(word)
);
return {
status: hasSpam ? 'failed' : 'passed',
message: hasSpam ? 'Content contains spam' : undefined
};
}
});
// Use built-in guardrails
const maxLength = builtinGuardrails.maxLength(500);
const minLength = builtinGuardrails.minLength(10);
const blockedWords = builtinGuardrails.blockedWords(['badword1', 'badword2']);
// Create manager
const manager = new GuardrailManager();
manager.add(noSpamGuardrail);
manager.add(maxLength);
manager.add(minLength);
manager.add(blockedWords);
// Test content
const testCases = [
'This is a normal, helpful response about programming.',
'BUY NOW! Free money if you click here!',
'Short',
'This is a valid response that provides useful information about TypeScript and its benefits for developers.'
];
console.log('=== Guardrail Tests ===\n');
for (const content of testCases) {
console.log(`Content: "${content.substring(0, 40)}..."`);
const result = await manager.runAll(content);
console.log(` Passed: ${result.passed}`);
if (!result.passed) {
result.results
.filter(r => r.status === 'failed')
.forEach(r => console.log(` Failed: ${r.message}`));
}
console.log();
}
// LLM Guardrail example
console.log('=== LLM Guardrail ===');
const llmGuard = new LLMGuardrail({
name: 'quality_check',
criteria: 'Content must be helpful and professional'
});
console.log('LLM Guardrail created:', llmGuard.name);
}
main().catch(console.error);
+62
View File
@@ -0,0 +1,62 @@
/**
* Knowledge Base (RAG) Example
* Demonstrates retrieval-augmented generation
*/
import { KnowledgeBase, createKnowledgeBase, Chunking } from 'praisonai';
async function main() {
// Create knowledge base
const kb = createKnowledgeBase();
// Add documents
const documents = [
{
id: 'ts-intro',
content: 'TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.',
metadata: { category: 'introduction', language: 'typescript' }
},
{
id: 'ts-types',
content: 'TypeScript adds optional static typing and class-based object-oriented programming to the language.',
metadata: { category: 'features', language: 'typescript' }
},
{
id: 'ts-benefits',
content: 'Benefits of TypeScript include catching errors early, better IDE support, and improved code maintainability.',
metadata: { category: 'benefits', language: 'typescript' }
},
{
id: 'js-intro',
content: 'JavaScript is a lightweight, interpreted programming language with first-class functions.',
metadata: { category: 'introduction', language: 'javascript' }
}
];
for (const doc of documents) {
await kb.add(doc);
}
console.log('Documents added:', kb.size);
// Search
console.log('\n=== Search: "TypeScript benefits" ===');
const results = await kb.search('TypeScript benefits', 3);
results.forEach(r => {
console.log(`Score: ${r.score.toFixed(2)} - ${r.document.content.substring(0, 50)}...`);
});
// Build context
console.log('\n=== Context for LLM ===');
const context = kb.buildContext(results);
console.log(context);
// Chunking example
console.log('\n=== Chunking Example ===');
const chunker = new Chunking({ chunkSize: 100, overlap: 20 });
const longText = 'This is a long document. '.repeat(20);
const chunks = chunker.chunk(longText);
console.log(`Chunked into ${chunks.length} pieces`);
}
main().catch(console.error);
+42
View File
@@ -0,0 +1,42 @@
/**
* Conversation Memory Example
* Demonstrates memory management for conversations
*/
import { Memory, createMemory } from 'praisonai';
async function main() {
const memory = createMemory({
maxEntries: 100,
maxTokens: 10000
});
// Simulate a conversation
await memory.add('What is TypeScript?', 'user');
await memory.add('TypeScript is a strongly typed programming language that builds on JavaScript.', 'assistant');
await memory.add('What are its main benefits?', 'user');
await memory.add('Key benefits include type safety, better IDE support, and easier refactoring.', 'assistant');
await memory.add('Can you give an example?', 'user');
console.log('Memory size:', memory.size, 'entries\n');
// Get recent messages
console.log('=== Recent Messages ===');
const recent = memory.getRecent(3);
recent.forEach(entry => {
console.log(`[${entry.role}]: ${entry.content.substring(0, 50)}...`);
});
// Search memory
console.log('\n=== Search Results for "TypeScript" ===');
const results = await memory.search('TypeScript');
results.forEach(r => {
console.log(`Score: ${r.score.toFixed(2)} - ${r.entry.content.substring(0, 40)}...`);
});
// Build context
console.log('\n=== Full Context ===');
console.log(memory.buildContext());
}
main().catch(console.error);
+60
View File
@@ -0,0 +1,60 @@
/**
* Observability Example
* Demonstrates tracing and monitoring
*/
import { MemoryObservabilityAdapter, ConsoleObservabilityAdapter } from 'praisonai';
async function main() {
// Memory adapter - stores traces in memory
const memoryAdapter = new MemoryObservabilityAdapter();
// Start a trace
const trace = memoryAdapter.startTrace('agent-execution');
console.log('Trace started:', trace.traceId);
// Create spans for different operations
const llmSpan = trace.startSpan('llm-call', 'llm');
llmSpan.setAttribute('model', 'gpt-4o-mini');
llmSpan.setAttribute('tokens', 150);
await new Promise(r => setTimeout(r, 100)); // Simulate work
llmSpan.end();
const toolSpan = trace.startSpan('tool-execution', 'tool');
toolSpan.setAttribute('tool', 'calculator');
toolSpan.addEvent('tool-started', { input: '2+2' });
await new Promise(r => setTimeout(r, 50)); // Simulate work
toolSpan.addEvent('tool-completed', { output: '4' });
toolSpan.end();
// End trace
trace.end();
// Retrieve trace data
const traceData = memoryAdapter.getTrace(trace.traceId);
console.log('\n=== Trace Data ===');
console.log('Trace ID:', traceData?.traceId);
console.log('Spans:', traceData?.spans.length);
console.log('Duration:', traceData?.endTime! - traceData?.startTime!, 'ms');
// Show spans
console.log('\n=== Spans ===');
traceData?.spans.forEach(span => {
console.log(`- ${span.name} (${span.kind}): ${span.endTime! - span.startTime}ms`);
if (span.attributes) {
Object.entries(span.attributes).forEach(([k, v]) => {
console.log(` ${k}: ${v}`);
});
}
});
// Console adapter example
console.log('\n=== Console Adapter ===');
const consoleAdapter = new ConsoleObservabilityAdapter();
const trace2 = consoleAdapter.startTrace('demo-trace');
const span = trace2.startSpan('demo-span', 'custom');
span.end();
trace2.end();
}
main().catch(console.error);
+71
View File
@@ -0,0 +1,71 @@
/**
* Planning System Example
* Demonstrates plans, steps, and todo lists
*/
import { Plan, PlanStep, TodoList, TodoItem, PlanStorage, createPlan, createTodoList } from 'praisonai';
async function main() {
// Create a project plan
console.log('=== Project Plan ===');
const plan = createPlan({
name: 'Build AI Agent',
description: 'Create a fully functional AI agent'
});
plan.addStep(new PlanStep({ description: 'Design agent architecture' }));
plan.addStep(new PlanStep({ description: 'Implement core functionality' }));
plan.addStep(new PlanStep({ description: 'Add tool support' }));
plan.addStep(new PlanStep({ description: 'Write tests' }));
plan.addStep(new PlanStep({ description: 'Deploy to production' }));
console.log('Plan:', plan.name);
console.log('Steps:', plan.steps.length);
// Execute steps
plan.start();
plan.steps[0].start();
plan.steps[0].complete();
plan.steps[1].start();
plan.steps[1].complete();
const progress = plan.getProgress();
console.log(`Progress: ${progress.completed}/${progress.total} (${progress.percentage}%)`);
// Create todo list
console.log('\n=== Todo List ===');
const todos = createTodoList('Sprint Tasks');
todos.add(new TodoItem({ content: 'Review PR #123', priority: 'high' }));
todos.add(new TodoItem({ content: 'Fix bug in router', priority: 'high' }));
todos.add(new TodoItem({ content: 'Update documentation', priority: 'medium' }));
todos.add(new TodoItem({ content: 'Refactor tests', priority: 'low' }));
console.log('Total items:', todos.items.length);
console.log('High priority:', todos.getByPriority('high').length);
// Complete some items
todos.items[0].complete();
todos.items[1].start();
console.log('Pending:', todos.getPending().length);
console.log('Completed:', todos.getCompleted().length);
const todoProgress = todos.getProgress();
console.log(`Progress: ${todoProgress.completed}/${todoProgress.total} (${todoProgress.percentage}%)`);
// Use storage
console.log('\n=== Plan Storage ===');
const storage = new PlanStorage();
storage.savePlan(plan);
storage.saveTodoList(todos);
console.log('Saved plans:', storage.listPlans().length);
console.log('Saved todo lists:', storage.listTodoLists().length);
// Retrieve
const retrieved = storage.getPlan(plan.id);
console.log('Retrieved plan:', retrieved?.name);
}
main().catch(console.error);
+74
View File
@@ -0,0 +1,74 @@
/**
* Skills System Example
* Demonstrates skill management and parsing
*/
import { SkillManager, parseSkillFile, createSkillManager } from 'praisonai';
async function main() {
// Parse a skill file
const skillContent = `---
name: code-review
description: Reviews code for best practices and potential issues
license: MIT
metadata:
author: praisonai
version: "1.0"
allowed-tools: Read Grep
---
# Code Review Skill
When reviewing code:
1. Check for syntax errors
2. Look for security vulnerabilities
3. Suggest performance improvements
4. Ensure proper error handling
`;
console.log('=== Parse Skill File ===');
const skill = parseSkillFile(skillContent);
console.log('Name:', skill.metadata.name);
console.log('Description:', skill.metadata.description);
console.log('License:', skill.metadata.license);
console.log('Instructions preview:', skill.instructions.substring(0, 100) + '...');
// Create skill manager
console.log('\n=== Skill Manager ===');
const manager = createSkillManager({ paths: [] });
// Register skills manually
manager.register({
metadata: {
name: 'typescript-expert',
description: 'Expert knowledge in TypeScript development'
},
instructions: 'You are a TypeScript expert. Help with type definitions, generics, and best practices.'
});
manager.register({
metadata: {
name: 'api-designer',
description: 'Designs RESTful APIs following best practices'
},
instructions: 'You design clean, RESTful APIs with proper versioning and documentation.'
});
// List skills
console.log('Registered skills:');
manager.list().forEach(s => {
console.log(`- ${s.metadata.name}: ${s.metadata.description}`);
});
// Get specific skill
const tsSkill = manager.get('typescript-expert');
console.log('\n=== TypeScript Expert Skill ===');
console.log('Instructions:', tsSkill?.instructions);
// Generate prompt
console.log('\n=== Generated Prompt ===');
const prompt = manager.generatePrompt(['typescript-expert']);
console.log(prompt.substring(0, 200) + '...');
}
main().catch(console.error);
+61
View File
@@ -0,0 +1,61 @@
/**
* Basic Tools Example
* Demonstrates tool creation and usage
*/
import { tool, ToolRegistry, getRegistry } from 'praisonai';
async function main() {
// Create tools
const calculator = tool({
name: 'calculator',
description: 'Perform basic math calculations',
parameters: {
type: 'object',
properties: {
expression: { type: 'string', description: 'Math expression to evaluate' }
},
required: ['expression']
},
execute: async ({ expression }) => {
try {
const result = eval(expression);
return `Result: ${result}`;
} catch (e) {
return 'Error: Invalid expression';
}
}
});
const greeter = tool({
name: 'greeter',
description: 'Generate a greeting',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name to greet' }
},
required: ['name']
},
execute: async ({ name }) => `Hello, ${name}! Welcome to PraisonAI.`
});
// Create registry and register tools
const registry = new ToolRegistry();
registry.register(calculator);
registry.register(greeter);
console.log('Registered tools:', registry.list().map(t => t.name));
// Execute tools
const calcResult = await calculator.execute({ expression: '10 * 5 + 2' });
console.log('\nCalculator:', calcResult);
const greetResult = await greeter.execute({ name: 'Developer' });
console.log('Greeter:', greetResult);
// Get OpenAI format
console.log('\nOpenAI tool format:', JSON.stringify(calculator.toOpenAITool(), null, 2));
}
main().catch(console.error);
+113
View File
@@ -0,0 +1,113 @@
/**
* Custom Tool Example
* Demonstrates creating custom tools using BaseTool class (plugin pattern)
*/
import { BaseTool, createTool, tool, ToolRegistry } from 'praisonai';
// Method 1: Extend BaseTool class (recommended for complex tools)
class WeatherTool extends BaseTool<{ location: string; units?: string }, { temp: number; condition: string }> {
name = 'get_weather';
description = 'Get current weather for a location';
parameters = {
type: 'object' as const,
properties: {
location: { type: 'string', description: 'City name' },
units: { type: 'string', description: 'celsius or fahrenheit', default: 'celsius' }
},
required: ['location']
};
async run(params: { location: string; units?: string }): Promise<{ temp: number; condition: string }> {
// Simulate API call
console.log(`Getting weather for ${params.location} in ${params.units || 'celsius'}`);
return { temp: 22, condition: 'sunny' };
}
}
// Method 2: Use createTool function (quick inline tools)
const calculatorTool = createTool({
name: 'calculator',
description: 'Evaluate a math expression',
parameters: {
type: 'object',
properties: {
expression: { type: 'string', description: 'Math expression to evaluate' }
},
required: ['expression']
},
run: (params: { expression: string }) => {
try {
return eval(params.expression);
} catch {
return 'Error: Invalid expression';
}
}
});
// Method 3: Use tool() function with config object
const greeterTool = tool({
name: 'greeter',
description: 'Generate a personalized greeting',
parameters: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name to greet' },
style: { type: 'string', description: 'Greeting style: formal or casual' }
},
required: ['name']
},
execute: async (params: { name: string; style?: string }) => {
if (params.style === 'formal') {
return `Good day, ${params.name}. How may I assist you?`;
}
return `Hey ${params.name}! What's up?`;
}
});
async function main() {
console.log('=== Custom Tool Examples ===\n');
// Test WeatherTool (class-based)
console.log('--- WeatherTool (class-based) ---');
const weather = new WeatherTool();
console.log('Name:', weather.name);
console.log('Description:', weather.description);
const weatherResult = await weather.run({ location: 'New York' });
console.log('Result:', weatherResult);
// Safe execution with error handling
const safeResult = await weather.safeRun({ location: 'London' });
console.log('Safe result:', safeResult);
// Get OpenAI schema
console.log('OpenAI Schema:', JSON.stringify(weather.getSchema(), null, 2));
// Test calculatorTool (createTool)
console.log('\n--- Calculator Tool (createTool) ---');
const calcResult = await calculatorTool.run({ expression: '10 * 5 + 2' });
console.log('10 * 5 + 2 =', calcResult);
// Test greeterTool (tool function)
console.log('\n--- Greeter Tool (tool function) ---');
const greeting1 = await greeterTool.execute({ name: 'Alice' });
console.log('Casual:', greeting1);
const greeting2 = await greeterTool.execute({ name: 'Mr. Smith', style: 'formal' });
console.log('Formal:', greeting2);
// Register tools in registry
console.log('\n--- Tool Registry ---');
const registry = new ToolRegistry();
registry.register(greeterTool);
console.log('Registered tools:', registry.list().map(t => t.name));
console.log('OpenAI tools format:', registry.toOpenAITools().length, 'tools');
// Validate tool
console.log('\n--- Validation ---');
console.log('WeatherTool valid:', weather.validate());
}
main().catch(console.error);
@@ -0,0 +1,57 @@
/**
* Pinecone Vector Store Example
*/
import { createPineconeStore } from 'praisonai';
async function main() {
const pinecone = createPineconeStore({
apiKey: process.env.PINECONE_API_KEY!
});
const indexName = 'test-index';
// Create index
console.log('Creating index...');
await pinecone.createIndex({
indexName,
dimension: 3,
metric: 'cosine'
});
// List indexes
const indexes = await pinecone.listIndexes();
console.log('Indexes:', indexes);
// Upsert vectors
console.log('Upserting vectors...');
await pinecone.upsert({
indexName,
vectors: [
{ id: 'vec-1', vector: [0.1, 0.2, 0.3], metadata: { category: 'A' } },
{ id: 'vec-2', vector: [0.4, 0.5, 0.6], metadata: { category: 'B' } },
{ id: 'vec-3', vector: [0.7, 0.8, 0.9], metadata: { category: 'A' } }
]
});
// Query
console.log('Querying...');
const results = await pinecone.query({
indexName,
vector: [0.1, 0.2, 0.3],
topK: 2,
includeMetadata: true
});
console.log('Results:');
for (const r of results) {
console.log(` ${r.id}: score=${r.score.toFixed(4)}, metadata=${JSON.stringify(r.metadata)}`);
}
// Cleanup
console.log('Deleting index...');
await pinecone.deleteIndex(indexName);
console.log('Done!');
}
main().catch(console.error);
+30
View File
@@ -0,0 +1,30 @@
/**
* Voice/TTS Example
*/
import { createOpenAIVoice } from '../../../src/praisonai-ts/src';
import { writeFileSync } from 'fs';
async function main() {
const voice = createOpenAIVoice({
apiKey: process.env.OPENAI_API_KEY
});
// Check available voices
const speakers = await voice.getSpeakers();
console.log('Available voices:', speakers.map(s => s.name).join(', '));
// Generate speech
console.log('Generating speech...');
const audio = await voice.speak('Hello! Welcome to PraisonAI TypeScript SDK.', {
voice: 'nova',
speed: 1.0,
format: 'mp3'
});
// Save to file
writeFileSync('output.mp3', audio);
console.log('Audio saved to output.mp3');
}
main().catch(console.error);
+29
View File
@@ -0,0 +1,29 @@
/**
* Basic Workflow Example
* Demonstrates sequential workflow execution
*/
import { Workflow, parallel, route, loop } from 'praisonai';
async function main() {
// Create a simple workflow
const workflow = new Workflow<string, string>('DataProcessor')
.step('validate', async (input) => {
console.log('Step 1: Validating input...');
return input.trim();
})
.step('transform', async (input) => {
console.log('Step 2: Transforming...');
return input.toUpperCase();
})
.step('format', async (input) => {
console.log('Step 3: Formatting...');
return `[PROCESSED] ${input}`;
});
const result = await workflow.run(' hello world ');
console.log('\nFinal output:', result.output);
console.log('Steps executed:', result.steps.length);
}
main().catch(console.error);
@@ -0,0 +1,48 @@
/**
* Conditional Workflow Example
* Demonstrates routing based on conditions
*/
import { route } from 'praisonai';
async function main() {
const processRequest = async (type: string) => {
console.log(`Processing request type: ${type}`);
const result = await route([
{
condition: () => type === 'urgent',
execute: async () => {
console.log(' -> Urgent handler activated');
return 'Processed urgently';
}
},
{
condition: () => type === 'normal',
execute: async () => {
console.log(' -> Normal handler activated');
return 'Processed normally';
}
},
{
condition: () => true, // Default
execute: async () => {
console.log(' -> Default handler activated');
return 'Processed with default handler';
}
}
]);
return result;
};
// Test different request types
const types = ['urgent', 'normal', 'unknown'];
for (const type of types) {
const result = await processRequest(type);
console.log(`Result: ${result}\n`);
}
}
main().catch(console.error);
@@ -0,0 +1,36 @@
/**
* Parallel Workflow Example
* Demonstrates parallel execution of tasks
*/
import { parallel } from 'praisonai';
async function main() {
console.log('Starting parallel tasks...\n');
const results = await parallel([
async () => {
console.log('Task 1: Starting...');
await new Promise(r => setTimeout(r, 1000));
console.log('Task 1: Complete');
return 'Result 1';
},
async () => {
console.log('Task 2: Starting...');
await new Promise(r => setTimeout(r, 500));
console.log('Task 2: Complete');
return 'Result 2';
},
async () => {
console.log('Task 3: Starting...');
await new Promise(r => setTimeout(r, 750));
console.log('Task 3: Complete');
return 'Result 3';
}
]);
console.log('\nAll tasks complete!');
console.log('Results:', results);
}
main().catch(console.error);
+163
View File
@@ -0,0 +1,163 @@
# PraisonAI MCP Server Examples
This directory contains examples for running PraisonAI as an MCP (Model Context Protocol) server.
## Overview
PraisonAI can expose its capabilities via MCP protocol, allowing integration with:
- Claude Desktop
- Cursor
- Windsurf
- VSCode MCP clients
- Any MCP-compatible client
## Protocol Version
These examples use MCP Protocol Version **2025-11-25**.
## Examples
### 1. STDIO Server (stdio_server.py)
Run PraisonAI as an MCP server using STDIO transport (for Claude Desktop integration).
```bash
# Run directly
python stdio_server.py
# Or via CLI
praisonai mcp serve --transport stdio
```
### 2. HTTP Stream Server (http_stream_server.py)
Run PraisonAI as an MCP server using HTTP Stream transport.
```bash
# Run directly
python http_stream_server.py
# Or via CLI
praisonai mcp serve --transport http-stream --port 8080
```
### 3. Custom Tools Server (custom_tools_server.py)
Register custom tools and expose them via MCP.
```bash
python custom_tools_server.py
```
### 4. Client Example (mcp_client_example.py)
Example of connecting to a PraisonAI MCP server as a client.
```bash
python mcp_client_example.py
```
## CLI Commands
```bash
# Start STDIO server
praisonai mcp serve --transport stdio
# Start HTTP Stream server
praisonai mcp serve --transport http-stream --port 8080
# Start with authentication
praisonai mcp serve --transport http-stream --api-key YOUR_KEY
# List available tools
praisonai mcp list-tools
# List available resources
praisonai mcp list-resources
# List available prompts
praisonai mcp list-prompts
# Generate client configuration
praisonai mcp config-generate --client claude-desktop
# Check server health
praisonai mcp doctor
```
## Client Configuration
### Claude Desktop
Add to `~/.config/claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"praisonai": {
"command": "praisonai",
"args": ["mcp", "serve", "--transport", "stdio"]
}
}
}
```
### Cursor
Add to Cursor settings:
```json
{
"mcpServers": {
"praisonai": {
"command": "praisonai",
"args": ["mcp", "serve", "--transport", "stdio"]
}
}
}
```
## Environment Variables
Set the following environment variables for full functionality:
```bash
export OPENAI_API_KEY=your_key
export ANTHROPIC_API_KEY=your_key # Optional
export GOOGLE_API_KEY=your_key # Optional
```
## Available Tools
Run `praisonai mcp list-tools` to see all available tools, including:
- `praisonai.chat.completion` - Chat with LLM
- `praisonai.agent.chat` - Chat with an agent
- `praisonai.agent.run` - Run a task with an agent
- `praisonai.workflow.run` - Run a workflow
- `praisonai.images.generate` - Generate images
- `praisonai.audio.transcribe` - Transcribe audio
- `praisonai.embed.create` - Create embeddings
- `praisonai.memory.*` - Memory operations
- `praisonai.knowledge.*` - Knowledge base operations
- And many more...
## Available Resources
- `praisonai://memory/sessions` - List memory sessions
- `praisonai://workflows` - List available workflows
- `praisonai://tools` - List available tools
- `praisonai://agents` - List agent configurations
- `praisonai://knowledge/sources` - List knowledge sources
- `praisonai://config` - Get current configuration
- `praisonai://mcp/status` - Get MCP server status
## Available Prompts
- `deep-research` - Generate deep research prompts
- `code-review` - Generate code review prompts
- `workflow-auto` - Generate workflow auto-generation prompts
- `guardrail-check` - Generate guardrail check prompts
- `context-engineering` - Generate context engineering prompts
- `eval-criteria` - Generate evaluation criteria prompts
- `agent-instructions` - Generate agent instructions prompts
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""
Custom Tools MCP Server Example
Register custom tools and expose them via MCP server.
Usage:
python custom_tools_server.py
"""
def main():
"""Run MCP server with custom tools."""
from praisonai.mcp_server.server import MCPServer
from praisonai.mcp_server.registry import register_tool, get_tool_registry
# Register custom tools
@register_tool("custom.greet")
def greet(name: str) -> str:
"""Greet a person by name."""
return f"Hello, {name}! Welcome to PraisonAI."
@register_tool("custom.calculate")
def calculate(expression: str) -> str:
"""Safely evaluate a mathematical expression."""
try:
# 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}"
@register_tool("custom.reverse")
def reverse_text(text: str) -> str:
"""Reverse a text string."""
return text[::-1]
@register_tool("custom.word_count")
def word_count(text: str) -> str:
"""Count words in text."""
words = text.split()
return f"Word count: {len(words)}"
# Show registered tools
registry = get_tool_registry()
tools = registry.list_all()
print(f"Registered {len(tools)} custom tools:")
for tool in tools:
print(f" - {tool.name}: {tool.description}")
print()
# Create and run server
server = MCPServer(
name="praisonai-custom",
version="1.0.0",
instructions="Custom tools MCP server example.",
)
print("Starting MCP server on http://127.0.0.1:8080/mcp")
server.run(
transport="http-stream",
host="127.0.0.1",
port=8080,
)
if __name__ == "__main__":
main()
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""
HTTP Stream MCP Server Example
Run PraisonAI as an MCP server using HTTP Stream transport.
This transport is useful for web-based integrations.
Usage:
python http_stream_server.py
Or via CLI:
praisonai mcp serve --transport http-stream --port 8080
"""
def main():
"""Run MCP server with HTTP Stream transport."""
from praisonai.mcp_server.server import MCPServer
from praisonai.mcp_server.adapters import register_all
# Register all tools, resources, and prompts
register_all()
# Create server
server = MCPServer(
name="praisonai",
version="1.0.0",
instructions="PraisonAI MCP Server - AI agent capabilities via MCP protocol.",
)
# Run with HTTP Stream transport
server.run(
transport="http-stream",
host="127.0.0.1",
port=8080,
endpoint="/mcp",
)
if __name__ == "__main__":
print("Starting PraisonAI MCP Server on http://127.0.0.1:8080/mcp")
print("Protocol Version: 2025-11-25")
print("Press Ctrl+C to stop")
main()
+238
View File
@@ -0,0 +1,238 @@
#!/usr/bin/env python3
"""
MCP Client Example
Example of connecting to a PraisonAI MCP server as a client.
Prerequisites:
1. Start the MCP server first:
praisonai mcp serve --transport http-stream --port 8080
2. Then run this client:
python mcp_client_example.py
Environment Variables:
OPENAI_API_KEY - Required for chat completion tools
"""
import requests
def main():
"""Connect to MCP server and call tools."""
base_url = "http://127.0.0.1:8080/mcp"
session_id = None
print("PraisonAI MCP Client Example")
print("=" * 40)
# 1. Initialize connection
print("\n1. Initializing connection...")
init_request = {
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {
"name": "example-client",
"version": "1.0.0",
},
},
}
response = requests.post(
base_url,
json=init_request,
headers={"Content-Type": "application/json"},
)
if response.status_code == 200:
result = response.json()
session_id = response.headers.get("MCP-Session-Id")
print(f" Connected! Session ID: {session_id}")
print(f" Server: {result.get('result', {}).get('serverInfo', {})}")
print(f" Protocol: {result.get('result', {}).get('protocolVersion')}")
else:
print(f" Error: {response.status_code}")
return
# 2. Send initialized notification
print("\n2. Sending initialized notification...")
init_notification = {
"jsonrpc": "2.0",
"method": "notifications/initialized",
}
requests.post(
base_url,
json=init_notification,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
print(" Done")
# 3. List available tools
print("\n3. Listing available tools...")
list_request = {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {},
}
response = requests.post(
base_url,
json=list_request,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
if response.status_code == 200:
result = response.json()
tools = result.get("result", {}).get("tools", [])
print(f" Found {len(tools)} tools")
for tool in tools[:5]: # Show first 5
print(f" - {tool.get('name')}")
if len(tools) > 5:
print(f" ... and {len(tools) - 5} more")
# 4. List available resources
print("\n4. Listing available resources...")
list_resources = {
"jsonrpc": "2.0",
"id": 3,
"method": "resources/list",
"params": {},
}
response = requests.post(
base_url,
json=list_resources,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
if response.status_code == 200:
result = response.json()
resources = result.get("result", {}).get("resources", [])
print(f" Found {len(resources)} resources")
for res in resources:
print(f" - {res.get('uri')}")
# 5. List available prompts
print("\n5. Listing available prompts...")
list_prompts = {
"jsonrpc": "2.0",
"id": 4,
"method": "prompts/list",
"params": {},
}
response = requests.post(
base_url,
json=list_prompts,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
if response.status_code == 200:
result = response.json()
prompts = result.get("result", {}).get("prompts", [])
print(f" Found {len(prompts)} prompts")
for prompt in prompts:
print(f" - {prompt.get('name')}")
# 6. Read a resource
print("\n6. Reading MCP status resource...")
read_resource = {
"jsonrpc": "2.0",
"id": 5,
"method": "resources/read",
"params": {
"uri": "praisonai://mcp/status",
},
}
response = requests.post(
base_url,
json=read_resource,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
if response.status_code == 200:
result = response.json()
contents = result.get("result", {}).get("contents", [])
if contents:
print(f" Status: {contents[0].get('text', 'N/A')}")
# 7. Get a prompt
print("\n7. Getting deep-research prompt...")
get_prompt = {
"jsonrpc": "2.0",
"id": 6,
"method": "prompts/get",
"params": {
"name": "deep-research",
"arguments": {
"topic": "AI agents",
"depth": "medium",
},
},
}
response = requests.post(
base_url,
json=get_prompt,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
if response.status_code == 200:
result = response.json()
messages = result.get("result", {}).get("messages", [])
if messages:
content = messages[0].get("content", {})
text = content.get("text", "") if isinstance(content, dict) else str(content)
print(f" Prompt preview: {text[:100]}...")
# 8. Ping
print("\n8. Pinging server...")
ping_request = {
"jsonrpc": "2.0",
"id": 7,
"method": "ping",
"params": {},
}
response = requests.post(
base_url,
json=ping_request,
headers={
"Content-Type": "application/json",
"MCP-Session-Id": session_id,
},
)
if response.status_code == 200:
print(" Pong!")
print("\n" + "=" * 40)
print("MCP client example completed successfully!")
if __name__ == "__main__":
main()
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python3
"""
STDIO MCP Server Example
Run PraisonAI as an MCP server using STDIO transport.
This is the recommended transport for Claude Desktop integration.
Usage:
python stdio_server.py
Or via CLI:
praisonai mcp serve --transport stdio
"""
def main():
"""Run MCP server with STDIO transport."""
from praisonai.mcp_server.server import MCPServer
from praisonai.mcp_server.adapters import register_all
# Register all tools, resources, and prompts
register_all()
# Create and run server
server = MCPServer(
name="praisonai",
version="1.0.0",
instructions="PraisonAI MCP Server - AI agent capabilities via MCP protocol.",
)
# Run with STDIO transport
server.run(transport="stdio")
if __name__ == "__main__":
main()
+101
View File
@@ -0,0 +1,101 @@
# Package Manager Example
This example demonstrates how to use the PraisonAI package manager for installing and managing Python packages with security defaults.
## Features Demonstrated
- Installing packages with version constraints
- Listing installed packages
- Searching for packages on PyPI
- Managing package index configuration
- Security features (dependency confusion prevention)
## Quick Start
```bash
# Run the example
python package_manager_example.py
```
## CLI Commands
### Install Packages
```bash
# Install a package
praisonai install requests
# Install with version constraint
praisonai install "requests>=2.28"
# Install multiple packages
praisonai install requests httpx aiohttp
# Upgrade existing package
praisonai install requests --upgrade
# JSON output
praisonai install requests --json
```
### Uninstall Packages
```bash
# Uninstall a package
praisonai uninstall requests
# Uninstall without confirmation
praisonai uninstall requests --yes
```
### List Packages
```bash
# List all installed packages
praisonai package list
# JSON output
praisonai package list --json
```
### Search Packages
```bash
# Search PyPI
praisonai package search langchain
# JSON output
praisonai package search langchain --json
```
### Index Configuration
```bash
# Show current index settings
praisonai package index show --json
# Set custom index
praisonai package index set https://pypi.mycompany.com/simple
# Reset to PyPI default
praisonai package index set https://pypi.org/simple
```
## Security Features
By default, only the primary index (PyPI) is used. Extra indexes are blocked to prevent dependency confusion attacks.
```bash
# This will FAIL (extra index not allowed by default)
praisonai install mypackage --extra-index-url https://other.index.com/simple
# Explicitly allow extra index (shows security warning)
praisonai install mypackage \
--extra-index-url https://other.index.com/simple \
--allow-extra-index
```
## Environment Variables
- `PRAISONAI_PACKAGE_INDEX_URL` - Override primary index URL
- `PIP_INDEX_URL` - Fallback to pip's index URL
@@ -0,0 +1,143 @@
#!/usr/bin/env python3
"""
Package Manager Example
This example demonstrates:
1. Checking package index configuration
2. Searching for packages on PyPI
3. Listing installed packages
4. Security features (safe defaults)
Requirements:
- praisonai installed
- No external API keys required
Note: This example does NOT actually install/uninstall packages
to avoid modifying your environment. It demonstrates read-only
operations and shows the commands for install/uninstall.
"""
import sys
import json
import subprocess
def run_command(args, description):
"""Run a praisonai command and display results."""
print(f"\n[{description}]")
print(f"Command: praisonai {' '.join(args)}")
print("-" * 40)
result = subprocess.run(
["python3", "-m", "praisonai"] + args,
capture_output=True,
text=True
)
if result.returncode == 0:
try:
data = json.loads(result.stdout)
print(json.dumps(data, indent=2))
return data
except json.JSONDecodeError:
print(result.stdout)
return None
else:
print(f"Error (exit code {result.returncode}):")
print(result.stderr or result.stdout)
return None
def main():
print("=" * 60)
print("PraisonAI Package Manager Example")
print("=" * 60)
print("\nThis example demonstrates package manager features.")
print("No packages will be installed or uninstalled.")
# 1. Show index configuration
print("\n" + "=" * 60)
print("1. PACKAGE INDEX CONFIGURATION")
print("=" * 60)
data = run_command(
["package", "index", "show", "--json"],
"Show current index settings"
)
if data:
print(f"\n✓ Primary index: {data.get('index_url', 'N/A')}")
print(f"✓ Extra indexes allowed: {data.get('allow_extra_index', False)}")
# 2. Search for packages
print("\n" + "=" * 60)
print("2. SEARCH PACKAGES")
print("=" * 60)
data = run_command(
["package", "search", "requests", "--json"],
"Search for 'requests' package"
)
if data and data.get("results"):
pkg = data["results"][0]
print(f"\n✓ Found: {pkg.get('name')} v{pkg.get('version')}")
print(f" Summary: {pkg.get('summary', 'N/A')}")
# 3. List installed packages (sample)
print("\n" + "=" * 60)
print("3. LIST INSTALLED PACKAGES")
print("=" * 60)
data = run_command(
["package", "list", "--json"],
"List installed packages"
)
if data and data.get("packages"):
print(f"\n✓ Total packages: {len(data['packages'])}")
print(" Sample (first 5):")
for pkg in data["packages"][:5]:
print(f" - {pkg['name']}=={pkg['version']}")
# 4. Show install/uninstall commands (without executing)
print("\n" + "=" * 60)
print("4. INSTALL/UNINSTALL COMMANDS (NOT EXECUTED)")
print("=" * 60)
print("\nTo install packages, use:")
print(" praisonai install requests")
print(" praisonai install 'requests>=2.28'")
print(" praisonai install requests httpx --upgrade")
print("\nTo uninstall packages, use:")
print(" praisonai uninstall requests")
print(" praisonai uninstall requests --yes")
# 5. Security features
print("\n" + "=" * 60)
print("5. SECURITY FEATURES")
print("=" * 60)
print("\nDependency Confusion Prevention:")
print(" - By default, only PyPI is used as package source")
print(" - Extra index URLs are blocked unless explicitly allowed")
print(" - Use --allow-extra-index to enable (shows warning)")
print("\nExample (blocked by default):")
print(" praisonai install pkg --extra-index-url https://other.index.com/simple")
print(" → Error: Extra index URLs not allowed")
print("\nExample (explicitly allowed):")
print(" praisonai install pkg --extra-index-url https://other.index.com/simple --allow-extra-index")
print(" → Warning shown, then proceeds")
print("\n" + "=" * 60)
print("Example completed!")
print("=" * 60)
return 0
if __name__ == "__main__":
sys.exit(main())
+108
View File
@@ -0,0 +1,108 @@
"""
Performance Benchmark Example for PraisonAI.
This example demonstrates how to measure and verify performance metrics
for PraisonAI CLI and SDK imports.
Usage:
python benchmark_example.py
"""
import time
import tracemalloc
import sys
def measure_import_time(module_name: str) -> float:
"""Measure import time for a module."""
# Clear from cache if already imported
if module_name in sys.modules:
del sys.modules[module_name]
start = time.time()
__import__(module_name)
elapsed = time.time() - start
return elapsed * 1000 # Return milliseconds
def measure_memory_usage(import_func) -> tuple:
"""Measure memory usage during import."""
tracemalloc.start()
import_func()
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
return current / 1024 / 1024, peak / 1024 / 1024 # Return MB
def main():
print("=" * 60)
print("PraisonAI Performance Benchmark")
print("=" * 60)
# Test 1: CLI Import Time
print("\n1. CLI Import Time")
print("-" * 40)
import os
os.environ['LOGLEVEL'] = 'WARNING'
start = time.time()
from praisonai.cli.main import PraisonAI
cli_import_time = (time.time() - start) * 1000
print(f" CLI import time: {cli_import_time:.0f}ms")
print(f" Status: {'✓ FAST' if cli_import_time < 500 else '✗ SLOW'}")
# Test 2: Memory Usage
print("\n2. Memory Usage")
print("-" * 40)
tracemalloc.start()
# Force re-import by clearing cache
for mod in list(sys.modules.keys()):
if 'praisonai' in mod:
del sys.modules[mod]
from praisonai.cli.main import PraisonAI as PraisonAI2
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f" Current memory: {current/1024/1024:.1f}MB")
print(f" Peak memory: {peak/1024/1024:.1f}MB")
print(f" Status: {'✓ LOW' if peak/1024/1024 < 50 else '✗ HIGH'}")
# Test 3: Lazy Loading Verification
print("\n3. Lazy Loading Verification")
print("-" * 40)
heavy_modules = ['litellm', 'instructor', 'praisonai.auto']
loaded = [m for m in heavy_modules if m in sys.modules]
if loaded:
print(f" Heavy modules loaded: {loaded}")
print(" Status: ✗ NOT LAZY")
else:
print(" Heavy modules NOT loaded at startup")
print(" Status: ✓ LAZY")
# Summary
print("\n" + "=" * 60)
print("Summary")
print("=" * 60)
all_pass = (
cli_import_time < 500 and
peak/1024/1024 < 50 and
len(loaded) == 0
)
if all_pass:
print("✓ All performance benchmarks PASSED")
else:
print("✗ Some benchmarks FAILED")
return 0 if all_pass else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
"""
Example: Lazy Imports & Fast Startup
Demonstrates how PraisonAI Agents uses lazy imports to achieve
fast startup times and reduced memory usage.
"""
import sys
import time
def example_verify_lazy_imports():
"""Verify that heavy dependencies are not loaded at import time."""
print("=" * 60)
print("Lazy Imports Verification")
print("=" * 60)
# Clear any cached imports
heavy_deps = ['litellm', 'chromadb', 'mem0', 'requests']
for dep in heavy_deps:
for key in list(sys.modules.keys()):
if key.startswith(dep):
del sys.modules[key]
# Measure import time
start = time.perf_counter()
import praisonaiagents
elapsed = (time.perf_counter() - start) * 1000
print(f"\nImport time: {elapsed:.1f}ms")
print(f"Target: <200ms")
print(f"Status: {'PASS' if elapsed < 200 else 'FAIL'}")
# Check lazy imports
print("\nLazy Import Check:")
all_lazy = True
for dep in heavy_deps:
is_lazy = dep not in sys.modules
status = "LAZY (good)" if is_lazy else "EAGER (bad)"
print(f" {dep}: {status}")
if not is_lazy:
all_lazy = False
print(f"\nAll lazy: {'PASS' if all_lazy else 'FAIL'}")
return all_lazy
def example_measure_memory():
"""Measure memory usage after import."""
print("\n" + "=" * 60)
print("Memory Usage Measurement")
print("=" * 60)
import tracemalloc
# Clear modules
for key in list(sys.modules.keys()):
if key.startswith('praisonaiagents'):
del sys.modules[key]
tracemalloc.start()
import praisonaiagents
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
current_mb = current / 1024 / 1024
peak_mb = peak / 1024 / 1024
print(f"\nCurrent memory: {current_mb:.1f}MB")
print(f"Peak memory: {peak_mb:.1f}MB")
print(f"Target: <30MB")
print(f"Status: {'PASS' if current_mb < 30 else 'WARN' if current_mb < 45 else 'FAIL'}")
return current_mb < 45
def example_specific_imports():
"""Show how to use specific imports for best performance."""
print("\n" + "=" * 60)
print("Specific Imports Example")
print("=" * 60)
# Good - specific imports are fast
print("\nGood practice - specific imports:")
print(" from praisonaiagents import Agent, Task")
# Avoid - star imports load everything
print("\nAvoid - star imports load more:")
print(" from praisonaiagents import *")
# Example of specific import
from praisonaiagents import Agent
print(f"\nAgent class loaded: {Agent.__name__}")
if __name__ == "__main__":
print("PraisonAI Agents - Lazy Imports Example")
print("=" * 60)
# Run examples
lazy_ok = example_verify_lazy_imports()
memory_ok = example_measure_memory()
example_specific_imports()
print("\n" + "=" * 60)
print("Summary")
print("=" * 60)
print(f"Lazy imports: {'PASS' if lazy_ok else 'FAIL'}")
print(f"Memory usage: {'PASS' if memory_ok else 'FAIL'}")
print(f"Overall: {'PASS' if lazy_ok and memory_ok else 'FAIL'}")
+149
View File
@@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
Example: Lite Agent (BYO-LLM)
Demonstrates the lightweight praisonaiagents.lite subpackage
that allows you to bring your own LLM client.
"""
import os
def example_custom_llm():
"""Example using a custom LLM function."""
print("=" * 60)
print("Example 1: Custom LLM Function")
print("=" * 60)
from praisonaiagents.lite import LiteAgent
# Define a simple mock LLM
def mock_llm(messages):
"""A mock LLM that echoes the last message."""
last_msg = messages[-1]["content"] if messages else "No message"
return f"Echo: {last_msg}"
agent = LiteAgent(
name="EchoAgent",
llm_fn=mock_llm,
instructions="You are a simple echo agent."
)
response = agent.chat("Hello, world!")
print(f"Response: {response}")
print(f"Chat history length: {len(agent.chat_history)}")
def example_openai_adapter():
"""Example using the built-in OpenAI adapter."""
print("\n" + "=" * 60)
print("Example 2: OpenAI Adapter")
print("=" * 60)
if not os.environ.get("OPENAI_API_KEY"):
print("Skipping: OPENAI_API_KEY not set")
return
from praisonaiagents.lite import LiteAgent, create_openai_llm_fn
# Create LLM function using OpenAI SDK directly
llm_fn = create_openai_llm_fn(model="gpt-4o-mini")
agent = LiteAgent(
name="OpenAIAgent",
llm_fn=llm_fn,
instructions="You are a helpful assistant. Keep responses brief."
)
response = agent.chat("What is 2+2?")
print(f"Response: {response}")
def example_with_tools():
"""Example using tools with LiteAgent."""
print("\n" + "=" * 60)
print("Example 3: Tools with LiteAgent")
print("=" * 60)
from praisonaiagents.lite import LiteAgent, tool
@tool
def add_numbers(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
@tool
def multiply_numbers(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b
def mock_llm(messages):
return "The calculation result is ready."
agent = LiteAgent(
name="MathAgent",
llm_fn=mock_llm,
tools=[add_numbers, multiply_numbers]
)
# Execute tools directly
result1 = agent.execute_tool("add_numbers", a=5, b=3)
print(f"5 + 3 = {result1.output}")
print(f"Success: {result1.success}")
result2 = agent.execute_tool("multiply_numbers", a=4, b=7)
print(f"4 * 7 = {result2.output}")
print(f"Success: {result2.success}")
def example_thread_safety():
"""Example demonstrating thread-safe operations."""
print("\n" + "=" * 60)
print("Example 4: Thread Safety")
print("=" * 60)
import threading
from praisonaiagents.lite import LiteAgent
counter = [0]
lock = threading.Lock()
def counting_llm(messages):
with lock:
counter[0] += 1
return f"Response {counter[0]}"
agent = LiteAgent(
name="ThreadSafeAgent",
llm_fn=counting_llm
)
def worker(thread_id):
for i in range(5):
agent.chat(f"Message from thread {thread_id}, iteration {i}")
threads = [
threading.Thread(target=worker, args=(i,))
for i in range(3)
]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"Total messages processed: {counter[0]}")
print(f"Chat history length: {len(agent.chat_history)}")
print("Thread safety test: PASS")
if __name__ == "__main__":
print("PraisonAI Agents - Lite Package Examples")
print("=" * 60)
example_custom_llm()
example_openai_adapter()
example_with_tools()
example_thread_safety()
print("\n" + "=" * 60)
print("All examples completed!")
+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env python3
"""
Runner for all performance examples.
Usage:
# Run without real API (mock only)
python run_all_examples.py
# Run with real API
RUN_REAL_KEY_TESTS=1 OPENAI_API_KEY=your-key python run_all_examples.py
"""
import os
import sys
import subprocess
def run_example(name, script_path):
"""Run an example script and report results."""
print(f"\n{'=' * 60}")
print(f"Running: {name}")
print("=" * 60)
result = subprocess.run(
[sys.executable, script_path],
capture_output=True,
text=True,
env=os.environ.copy()
)
print(result.stdout)
if result.stderr:
print(f"STDERR: {result.stderr}")
return result.returncode == 0
def main():
"""Run all performance examples."""
print("PraisonAI Agents - Performance Examples Runner")
print("=" * 60)
# Check environment
real_tests = os.environ.get("RUN_REAL_KEY_TESTS")
has_openai = bool(os.environ.get("OPENAI_API_KEY"))
print(f"RUN_REAL_KEY_TESTS: {real_tests or 'not set'}")
print(f"OPENAI_API_KEY: {'set' if has_openai else 'not set'}")
# Get script directory
script_dir = os.path.dirname(os.path.abspath(__file__))
# Define examples
examples = [
("Lazy Imports", os.path.join(script_dir, "lazy_imports_example.py")),
("Lite Agent", os.path.join(script_dir, "lite_agent_example.py")),
("Thread Safety", os.path.join(script_dir, "thread_safety_example.py")),
]
# Run examples
results = []
for name, path in examples:
if os.path.exists(path):
success = run_example(name, path)
results.append((name, success))
else:
print(f"Skipping {name}: {path} not found")
results.append((name, None))
# Summary
print("\n" + "=" * 60)
print("Summary")
print("=" * 60)
passed = 0
failed = 0
skipped = 0
for name, success in results:
if success is None:
status = "SKIPPED"
skipped += 1
elif success:
status = "PASS"
passed += 1
else:
status = "FAIL"
failed += 1
print(f" {name}: {status}")
print(f"\nTotal: {passed} passed, {failed} failed, {skipped} skipped")
return 0 if failed == 0 else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,158 @@
#!/usr/bin/env python3
"""
Example: Thread-Safe Agent State
Demonstrates thread-safe chat history and cache management
in PraisonAI Agents.
"""
import os
import threading
import time
def example_lite_agent_thread_safety():
"""Demonstrate thread safety with LiteAgent."""
print("=" * 60)
print("Example 1: LiteAgent Thread Safety")
print("=" * 60)
from praisonaiagents.lite import LiteAgent
# Counter for tracking responses
response_count = [0]
count_lock = threading.Lock()
def counting_llm(messages):
with count_lock:
response_count[0] += 1
return f"Response #{response_count[0]}"
agent = LiteAgent(
name="ThreadSafeAgent",
llm_fn=counting_llm
)
errors = []
def worker(thread_id):
try:
for i in range(10):
agent.chat(f"Thread {thread_id}, message {i}")
except Exception as e:
errors.append(e)
# Create and start threads
threads = [
threading.Thread(target=worker, args=(i,))
for i in range(5)
]
start = time.perf_counter()
for t in threads:
t.start()
for t in threads:
t.join()
elapsed = time.perf_counter() - start
print(f"Threads: 5")
print(f"Messages per thread: 10")
print(f"Total messages: {response_count[0]}")
print(f"Chat history length: {len(agent.chat_history)}")
print(f"Errors: {len(errors)}")
print(f"Time: {elapsed:.2f}s")
print(f"Status: {'PASS' if len(errors) == 0 else 'FAIL'}")
def example_agent_locks():
"""Verify Agent class has proper locks."""
print("\n" + "=" * 60)
print("Example 2: Agent Lock Verification")
print("=" * 60)
from praisonaiagents import Agent
agent = Agent(
name="LockTestAgent",
instructions="Test agent",
verbose=False
)
# Check for locks
has_history_lock = hasattr(agent, '_history_lock')
has_cache_lock = hasattr(agent, '_cache_lock')
print(f"Has _history_lock: {has_history_lock}")
print(f"Has _cache_lock: {has_cache_lock}")
# Verify lock types
if has_history_lock:
lock_type = type(agent._history_lock).__name__
print(f"_history_lock type: {lock_type}")
if has_cache_lock:
lock_type = type(agent._cache_lock).__name__
print(f"_cache_lock type: {lock_type}")
print(f"Status: {'PASS' if has_history_lock and has_cache_lock else 'FAIL'}")
def example_concurrent_real_api():
"""Demonstrate concurrent API calls (requires API key)."""
print("\n" + "=" * 60)
print("Example 3: Concurrent Real API Calls")
print("=" * 60)
if not os.environ.get("OPENAI_API_KEY"):
print("Skipping: OPENAI_API_KEY not set")
return
from praisonaiagents import Agent
agent = Agent(
name="ConcurrentAgent",
instructions="Reply with one word only.",
llm="gpt-4o-mini",
verbose=False
)
results = []
results_lock = threading.Lock()
errors = []
def worker(thread_id):
try:
response = agent.chat(f"Say hello {thread_id}")
with results_lock:
results.append((thread_id, response))
except Exception as e:
errors.append(e)
threads = [
threading.Thread(target=worker, args=(i,))
for i in range(3)
]
start = time.perf_counter()
for t in threads:
t.start()
for t in threads:
t.join()
elapsed = time.perf_counter() - start
print(f"Concurrent requests: 3")
print(f"Successful responses: {len(results)}")
print(f"Errors: {len(errors)}")
print(f"Time: {elapsed:.2f}s")
print(f"Status: {'PASS' if len(errors) == 0 else 'FAIL'}")
if __name__ == "__main__":
print("PraisonAI Agents - Thread Safety Examples")
print("=" * 60)
example_lite_agent_thread_safety()
example_agent_locks()
example_concurrent_real_api()
print("\n" + "=" * 60)
print("All examples completed!")
+80
View File
@@ -0,0 +1,80 @@
# Policy Packs Example
This example demonstrates how to use PraisonAI policy packs for managing tool permissions, data policies, and execution modes.
## Features Demonstrated
- Creating and loading policy packs
- Tool permission checking (allow/deny)
- Policy modes (dev/prod)
- Merging policies
- Data and PII policies
## Quick Start
```bash
python policy_example.py
```
## CLI Commands
```bash
# Show default policy
praisonai recipe policy show
# Show policy from file
praisonai recipe policy show my-policy.yaml
# Create policy template
praisonai recipe policy init -o my-policy.yaml
# Validate policy file
praisonai recipe policy validate my-policy.yaml
```
## Policy File Format
```yaml
name: my-org-policy
version: "1.0"
tools:
allow:
- web.search
- db.query
deny:
- shell.exec
- file.write
network:
allow_domains:
- api.openai.com
deny_domains:
- localhost
pii:
mode: redact # allow, deny, redact
fields:
- email
- phone
data:
retention_days: 30
export_allowed: true
modes:
dev:
allow_interactive_prompts: true
strict_tool_enforcement: false
prod:
allow_interactive_prompts: false
strict_tool_enforcement: true
require_auth: true
```
## Using Policy with Recipe Run
```bash
# Run with policy file
praisonai recipe run my-recipe --policy my-policy.yaml --mode prod
```
+215
View File
@@ -0,0 +1,215 @@
#!/usr/bin/env python3
"""
PraisonAI Policy Packs Example
This example demonstrates:
1. Creating and loading policy packs
2. Tool permission checking
3. Policy modes (dev/prod)
4. Merging policies
Prerequisites:
- pip install praisonai
Usage:
python policy_example.py
"""
import tempfile
from pathlib import Path
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Policy Packs Example")
print("=" * 60)
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
# =====================================================
# Default Policies
# =====================================================
print("\n" + "=" * 40)
print("Default Policies")
print("=" * 40)
from praisonai.recipe.policy import get_default_policy, PolicyPack, PolicyDeniedError
print("\n1. Loading default dev policy...")
dev_policy = get_default_policy("dev")
print(f" Name: {dev_policy.name}")
print(f" Allowed tools: {len(dev_policy.allowed_tools)}")
print(f" Denied tools: {len(dev_policy.denied_tools)}")
print(f" PII mode: {dev_policy.pii_mode}")
print("\n2. Loading default prod policy...")
prod_policy = get_default_policy("prod")
print(f" Name: {prod_policy.name}")
print(f" PII mode: {prod_policy.pii_mode}")
# =====================================================
# Tool Permission Checking
# =====================================================
print("\n" + "=" * 40)
print("Tool Permission Checking")
print("=" * 40)
print("\n3. Checking tool permissions...")
# Check allowed tool
try:
dev_policy.check_tool("web.search")
print(" web.search: ✓ Allowed")
except PolicyDeniedError as e:
print(f" web.search: ✗ Denied - {e}")
# Check denied tool
try:
dev_policy.check_tool("shell.exec")
print(" shell.exec: ✓ Allowed")
except PolicyDeniedError:
print(" shell.exec: ✗ Denied")
# Check another denied tool
try:
dev_policy.check_tool("file.write")
print(" file.write: ✓ Allowed")
except PolicyDeniedError:
print(" file.write: ✗ Denied")
# =====================================================
# Custom Policy Pack
# =====================================================
print("\n" + "=" * 40)
print("Custom Policy Pack")
print("=" * 40)
print("\n4. Creating custom policy pack...")
custom_policy = PolicyPack(
name="my-org-policy",
config={
"tools": {
"allow": ["web.search", "db.query", "file.read"],
"deny": ["shell.exec", "network.unrestricted"],
},
"network": {
"allow_domains": ["api.openai.com", "api.anthropic.com"],
"deny_domains": ["localhost", "127.0.0.1"],
},
"pii": {
"mode": "redact",
"fields": ["email", "phone", "ssn"],
},
"data": {
"retention_days": 30,
"export_allowed": True,
},
"modes": {
"dev": {
"allow_interactive_prompts": True,
"strict_tool_enforcement": False,
},
"prod": {
"allow_interactive_prompts": False,
"strict_tool_enforcement": True,
"require_auth": True,
},
},
},
)
print(f" Name: {custom_policy.name}")
print(f" Allowed tools: {list(custom_policy.allowed_tools)}")
print(f" PII mode: {custom_policy.pii_mode}")
print(f" Retention days: {custom_policy.retention_days}")
# =====================================================
# Saving and Loading Policies
# =====================================================
print("\n" + "=" * 40)
print("Saving and Loading Policies")
print("=" * 40)
print("\n5. Saving policy to file...")
policy_file = tmp_path / "my-policy.yaml"
custom_policy.save(policy_file)
print(f" Saved to: {policy_file}")
print("\n6. Loading policy from file...")
loaded_policy = PolicyPack.load(policy_file)
print(f" Loaded: {loaded_policy.name}")
print(f" PII mode: {loaded_policy.pii_mode}")
# =====================================================
# Merging Policies
# =====================================================
print("\n" + "=" * 40)
print("Merging Policies")
print("=" * 40)
print("\n7. Creating base and override policies...")
base_policy = PolicyPack(
name="base",
config={
"tools": {"allow": ["web.search"]},
"pii": {"mode": "allow"},
},
)
override_policy = PolicyPack(
name="override",
config={
"tools": {"allow": ["db.query"]},
"pii": {"mode": "redact", "fields": ["email"]},
},
)
print("\n8. Merging policies...")
merged = base_policy.merge(override_policy)
print(f" Merged name: {merged.name}")
print(f" Allowed tools: {list(merged.allowed_tools)}")
print(f" PII mode: {merged.pii_mode}")
# =====================================================
# Mode-Specific Configuration
# =====================================================
print("\n" + "=" * 40)
print("Mode-Specific Configuration")
print("=" * 40)
print("\n9. Getting mode-specific config...")
dev_config = custom_policy.get_mode_config("dev")
prod_config = custom_policy.get_mode_config("prod")
print(" Dev mode:")
print(f" - Interactive prompts: {dev_config.get('allow_interactive_prompts')}")
print(f" - Strict enforcement: {dev_config.get('strict_tool_enforcement')}")
print(" Prod mode:")
print(f" - Interactive prompts: {prod_config.get('allow_interactive_prompts')}")
print(f" - Strict enforcement: {prod_config.get('strict_tool_enforcement')}")
print(f" - Require auth: {prod_config.get('require_auth')}")
# =====================================================
# Data Policy
# =====================================================
print("\n" + "=" * 40)
print("Data Policy")
print("=" * 40)
print("\n10. Getting data policy...")
data_policy = custom_policy.get_data_policy()
print(f" PII mode: {data_policy['pii']['mode']}")
print(f" PII fields: {data_policy['pii']['fields']}")
print(f" Retention days: {data_policy['retention_days']}")
print(f" Export allowed: {data_policy['export_allowed']}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
@@ -0,0 +1,11 @@
# Creator Suite Examples - Environment Variables
# Required for most features
OPENAI_API_KEY=your_openai_api_key_here
# Optional - for web search in news crawler
TAVILY_API_KEY=your_tavily_api_key_here
# Optional - for additional LLM providers
ANTHROPIC_API_KEY=your_anthropic_api_key_here
GOOGLE_API_KEY=your_google_api_key_here
+77
View File
@@ -0,0 +1,77 @@
# Creator Suite Examples
Examples for the PraisonAI Creator Automation Suite - a complete toolkit for AI content creators.
## Quick Start
```bash
# Set your API key
export OPENAI_API_KEY=your_key_here
# Run an example
python news_crawler_example.py
python script_writer_example.py
python hook_generator_example.py
python brief_generator_example.py
```
## Examples
| Example | Description | API Key Required |
|---------|-------------|------------------|
| `news_crawler_example.py` | Crawl AI news from multiple sources | No (HN, arXiv) |
| `script_writer_example.py` | Generate scripts for YouTube, X, LinkedIn | Yes (OpenAI) |
| `hook_generator_example.py` | Generate attention-grabbing hooks | Yes (OpenAI) |
| `brief_generator_example.py` | Generate news briefs | Yes (OpenAI) |
## Environment Variables
Copy `.env.example` to `.env` and fill in your API keys:
```bash
cp .env.example .env
```
## Features Covered
### News Intelligence Layer
- AI News Crawler
- AI News Deduper
- AI Signal Ranker
- AI Context Enricher
- AI Brief Generator
### Script & Story Layer
- AI Script Writer
- AI Angle Generator
- AI Hook Generator
- AI CTA Generator
- AI Fact Checker
### Capture & Screen Automation
- AI Screenshot Capture
- AI Screen Recorder
- AI News Capture Pack
### Video Generation
- AI B-roll Builder
- AI Voiceover Generator
- AI Video Merger
### Publishing & Distribution
- AI Publisher Pack
- AI Content Calendar
- AI Post Copy Generator
- AI Hashtag Optimizer
### Feedback & Learning
- AI Performance Analyzer
- AI Comment Miner
- AI A/B Hook Tester
### Orchestrator
- AI Daily News Show (end-to-end pipeline)
## Documentation
Full documentation: https://docs.praison.ai/docs/ai-tools/creator-suite/
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""
AI Brief Generator Example
Demonstrates generating news briefs from articles.
Requires: OPENAI_API_KEY
"""
import os
import sys
# Check for API key
if not os.environ.get("OPENAI_API_KEY"):
print("ERROR: OPENAI_API_KEY environment variable required")
print("Set it with: export OPENAI_API_KEY=your_key")
sys.exit(1)
# Add the Agent-Recipes templates to path
sys.path.insert(0, '/Users/praison/Agent-Recipes/agent_recipes/templates/ai-brief-generator')
from tools import generate_brief, extract_highlights
def main():
print("=" * 60)
print("AI Brief Generator Example")
print("=" * 60)
# Sample articles
articles = [
{
"title": "OpenAI Releases GPT-5 with Multimodal Capabilities",
"content": "OpenAI announced GPT-5 today with major improvements in reasoning, multimodal understanding, and reduced hallucinations.",
"source": "TechCrunch",
"url": "https://example.com/gpt5"
},
{
"title": "Google Gemini 2.0 Launches with Real-time Video Understanding",
"content": "Google unveiled Gemini 2.0 with breakthrough capabilities in real-time video analysis and native tool use.",
"source": "The Verge",
"url": "https://example.com/gemini2"
},
{
"title": "Anthropic Claude 4 Sets New Benchmarks",
"content": "Anthropic's Claude 4 achieves state-of-the-art results on coding, math, and reasoning benchmarks.",
"source": "Wired",
"url": "https://example.com/claude4"
}
]
# 1. Generate daily brief
print("\n1. Generating daily brief...")
brief = generate_brief(articles, format="daily", max_articles=3)
print(f" Format: daily")
print(f" Articles included: {brief.get('article_count', 0)}")
print(f"\n Brief preview:\n {brief.get('brief', '')[:500]}...")
# 2. Extract highlights
print("\n2. Extracting highlights...")
highlights = extract_highlights(articles, num_highlights=3)
print(f" Highlights:")
for h in highlights.get('highlights', []):
print(f" - {h}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""
AI Hook Generator Example
Demonstrates generating attention-grabbing hooks.
Requires: OPENAI_API_KEY
"""
import os
import sys
# Check for API key
if not os.environ.get("OPENAI_API_KEY"):
print("ERROR: OPENAI_API_KEY environment variable required")
print("Set it with: export OPENAI_API_KEY=your_key")
sys.exit(1)
# Add the Agent-Recipes templates to path
sys.path.insert(0, '/Users/praison/Agent-Recipes/agent_recipes/templates/ai-hook-generator')
from tools import generate_hooks, rank_hooks
def main():
print("=" * 60)
print("AI Hook Generator Example")
print("=" * 60)
topic = "GPT-5 just released with groundbreaking capabilities"
# 1. Generate hooks
print(f"\n1. Generating hooks for: '{topic}'")
hooks = generate_hooks(topic, num_variants=5)
print(f" Generated {len(hooks.get('hooks', []))} hooks:")
for hook in hooks.get('hooks', []):
print(f"\n [{hook.get('style', 'unknown')}]")
print(f" {hook.get('text', '')}")
# 2. Rank hooks
print("\n2. Ranking hooks by engagement potential...")
ranked = rank_hooks(hooks.get('hooks', []))
best = ranked.get('best_hook', {})
print(f"\n Best hook (score: {best.get('score', 0)}):")
print(f" {best.get('text', '')}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""
AI News Crawler Example
Demonstrates crawling AI news from multiple sources.
"""
import os
import sys
# Add the Agent-Recipes templates to path
sys.path.insert(0, '/Users/praison/Agent-Recipes/agent_recipes/templates/ai-news-crawler')
from tools import crawl_hackernews, crawl_reddit_ai, crawl_arxiv, crawl_ai_news
def main():
print("=" * 60)
print("AI News Crawler Example")
print("=" * 60)
# 1. Crawl HackerNews (no API key needed)
print("\n1. Crawling HackerNews...")
hn_articles = crawl_hackernews(max_articles=5, time_window_hours=48)
print(f" Found {len(hn_articles)} articles from HackerNews")
for article in hn_articles[:3]:
print(f" - {article.get('title', 'No title')[:60]}...")
# 2. Crawl arXiv (no API key needed)
print("\n2. Crawling arXiv...")
arxiv_articles = crawl_arxiv(categories=["cs.AI", "cs.LG"], max_results=5)
print(f" Found {len(arxiv_articles)} articles from arXiv")
for article in arxiv_articles[:3]:
print(f" - {article.get('title', 'No title')[:60]}...")
# 3. Full crawl from multiple sources
print("\n3. Full multi-source crawl...")
all_articles = crawl_ai_news(
sources=["hackernews", "arxiv"],
max_articles=10,
time_window_hours=48
)
print(f" Total articles: {all_articles.get('total', 0)}")
print(f" Sources crawled: {all_articles.get('sources_crawled', [])}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
AI Script Writer Example
Demonstrates generating scripts for different platforms.
Requires: OPENAI_API_KEY
"""
import os
import sys
# Check for API key
if not os.environ.get("OPENAI_API_KEY"):
print("ERROR: OPENAI_API_KEY environment variable required")
print("Set it with: export OPENAI_API_KEY=your_key")
sys.exit(1)
# Add the Agent-Recipes templates to path
sys.path.insert(0, '/Users/praison/Agent-Recipes/agent_recipes/templates/ai-script-writer')
from tools import write_youtube_script, write_short_script, write_thread
def main():
print("=" * 60)
print("AI Script Writer Example")
print("=" * 60)
topic = "AI agents are revolutionizing software development"
# 1. YouTube Long-form Script
print("\n1. Generating YouTube long-form script...")
yt_script = write_youtube_script(
topic=topic,
target_length=180,
key_points=["automation", "productivity", "future of coding"]
)
print(f" Format: {yt_script.get('format')}")
print(f" Estimated duration: {yt_script.get('estimated_duration')}s")
print(f" Script preview:\n {yt_script.get('script', '')[:200]}...")
# 2. YouTube Short Script
print("\n2. Generating YouTube Short script...")
short_script = write_short_script(topic, duration=30)
print(f" Format: {short_script.get('format')}")
print(f" Script:\n {short_script.get('script', '')[:300]}...")
# 3. X Thread
print("\n3. Generating X thread...")
thread = write_thread(topic, num_tweets=3)
print(f" Thread ({len(thread.get('tweets', []))} tweets):")
for i, tweet in enumerate(thread.get('tweets', [])[:3], 1):
print(f" Tweet {i}: {tweet[:80]}...")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env python3
"""
Example: LLM-based Recipes
Demonstrates usage of LLM-powered recipes:
- ai-blog-generator
- ai-social-media-generator
- ai-faq-generator
- ai-sentiment-analyzer
"""
import os
import sys
# Ensure API key is set
if not os.environ.get("OPENAI_API_KEY"):
print("Please set OPENAI_API_KEY environment variable")
sys.exit(1)
# Add recipe tools to path
sys.path.insert(0, "/Users/praison/PraisonAI-tools/praisonai_tools/recipe_tools")
from llm_tool import LLMTool, llm_complete
def example_blog_generator():
"""Generate a blog post."""
print("\n=== AI Blog Generator ===")
llm = LLMTool(provider="openai", model="gpt-4o-mini")
topic = "The Future of AI in Healthcare"
response = llm.complete(
f"""Write a short blog post (3 paragraphs) about: {topic}
Include:
- Engaging introduction
- Key points
- Call to action
Format as markdown.""",
system="You are an expert blog writer specializing in technology topics.",
max_tokens=500,
)
print(f"Topic: {topic}")
print(f"\nGenerated Blog Post:\n{response.content}")
print(f"\nTokens used: {response.usage.get('total_tokens', 'N/A')}")
def example_social_media_generator():
"""Generate social media posts."""
print("\n=== AI Social Media Generator ===")
llm = LLMTool(provider="openai", model="gpt-4o-mini")
content = "We just launched our new AI-powered productivity app!"
response = llm.complete(
f"""Create social media posts for the following announcement:
{content}
Generate posts for:
1. Twitter (280 chars max)
2. LinkedIn (professional tone)
3. Instagram (with emoji suggestions)
Format each clearly.""",
system="You are a social media marketing expert.",
max_tokens=400,
)
print(f"Content: {content}")
print(f"\nGenerated Posts:\n{response.content}")
def example_faq_generator():
"""Generate FAQ from content."""
print("\n=== AI FAQ Generator ===")
llm = LLMTool(provider="openai", model="gpt-4o-mini")
documentation = """
Our product is a cloud-based project management tool.
It supports team collaboration, task tracking, and reporting.
Pricing starts at $10/month per user.
We offer a 14-day free trial.
Integration with Slack, GitHub, and Jira is available.
"""
response = llm.complete(
f"""Based on this documentation, generate 5 FAQ questions and answers:
{documentation}
Format as:
Q: [question]
A: [answer]
""",
system="You are a technical writer creating FAQ documentation.",
max_tokens=400,
)
print(f"Generated FAQ:\n{response.content}")
def example_sentiment_analyzer():
"""Analyze sentiment in text."""
print("\n=== AI Sentiment Analyzer ===")
llm = LLMTool(provider="openai", model="gpt-4o-mini")
reviews = [
"This product is amazing! Best purchase ever.",
"Terrible experience. Would not recommend.",
"It's okay, nothing special but does the job.",
]
for review in reviews:
response = llm.complete(
f"""Analyze the sentiment of this text and respond with ONLY one word: POSITIVE, NEGATIVE, or NEUTRAL
Text: {review}""",
max_tokens=10,
)
print(f"Review: {review[:50]}...")
print(f"Sentiment: {response.content.strip()}\n")
if __name__ == "__main__":
print("=" * 60)
print("LLM-Based Recipes Examples")
print("=" * 60)
example_blog_generator()
example_social_media_generator()
example_faq_generator()
example_sentiment_analyzer()
print("\n" + "=" * 60)
print("All examples completed!")
print("=" * 60)
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
"""
Run All Recipes - Test harness for all Agent-Recipes.
Runs each recipe in dry-run mode to verify CLI parity and run.json generation.
Requires: OPENAI_API_KEY environment variable for integration tests.
"""
import json
import os
import subprocess
import sys
from dataclasses import dataclass
from typing import List
# Recipe definitions
RECIPES = [
"ai-audio-normalizer",
"ai-audio-splitter",
"ai-changelog-generator",
"ai-code-documenter",
"ai-csv-cleaner",
"ai-data-profiler",
"ai-dependency-auditor",
"ai-doc-translator",
"ai-folder-packager",
"ai-image-cataloger",
"ai-image-optimizer",
"ai-image-resizer",
"ai-json-to-csv",
"ai-markdown-to-pdf",
"ai-pdf-summarizer",
"ai-pdf-to-markdown",
"ai-podcast-cleaner",
"ai-repo-readme",
"ai-schema-generator",
"ai-screenshot-ocr",
"ai-sitemap-scraper",
"ai-slide-to-notes",
"ai-url-to-markdown",
"ai-video-editor",
"ai-video-thumbnails",
"ai-video-to-gif",
]
@dataclass
class TestResult:
"""Result of a recipe test."""
recipe: str
status: str # pass, fail, skip
reason: str = ""
duration: float = 0.0
def check_api_keys() -> dict:
"""Check available API keys."""
keys = {
"OPENAI_API_KEY": bool(os.environ.get("OPENAI_API_KEY")),
"ANTHROPIC_API_KEY": bool(os.environ.get("ANTHROPIC_API_KEY")),
"GOOGLE_API_KEY": bool(os.environ.get("GOOGLE_API_KEY")),
}
return keys
def check_external_deps() -> dict:
"""Check external dependencies."""
import shutil
deps = {
"ffmpeg": shutil.which("ffmpeg") is not None,
"ffprobe": shutil.which("ffprobe") is not None,
"pdftotext": shutil.which("pdftotext") is not None,
"pandoc": shutil.which("pandoc") is not None,
"git": shutil.which("git") is not None,
}
return deps
def run_recipe_dry_run(recipe: str, timeout: int = 30) -> TestResult:
"""Run a recipe in dry-run mode."""
import time
start = time.time()
try:
# Use praison templates run command with dry-run
cmd = ["praison", "templates", "run", recipe, "--dry-run", "dummy_input"]
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout,
)
duration = time.time() - start
if result.returncode == 0:
return TestResult(recipe, "pass", "dry-run completed", duration)
else:
# Check if it's a missing dependency error
stderr = result.stderr.lower()
if "not found" in stderr or "missing" in stderr:
return TestResult(recipe, "skip", f"Missing dependency: {result.stderr[:100]}", duration)
return TestResult(recipe, "fail", f"Exit code {result.returncode}: {result.stderr[:100]}", duration)
except subprocess.TimeoutExpired:
return TestResult(recipe, "fail", "Timeout", timeout)
except FileNotFoundError:
return TestResult(recipe, "skip", "praison CLI not found", 0)
except Exception as e:
return TestResult(recipe, "fail", str(e), 0)
def run_all_recipes(dry_run_only: bool = True) -> List[TestResult]:
"""Run all recipes and collect results."""
results = []
print("=" * 60)
print("RECIPE TEST HARNESS")
print("=" * 60)
# Check prerequisites
keys = check_api_keys()
deps = check_external_deps()
print("\nAPI Keys:")
for key, present in keys.items():
status = "✓" if present else "✗"
print(f" {status} {key}")
print("\nExternal Dependencies:")
for dep, present in deps.items():
status = "✓" if present else "✗"
print(f" {status} {dep}")
print("\n" + "=" * 60)
print(f"Running {len(RECIPES)} recipes (dry-run={dry_run_only})")
print("=" * 60 + "\n")
for i, recipe in enumerate(RECIPES, 1):
print(f"[{i:2d}/{len(RECIPES)}] {recipe}...", end=" ", flush=True)
if dry_run_only:
result = run_recipe_dry_run(recipe)
else:
# Full run would go here
result = run_recipe_dry_run(recipe)
results.append(result)
if result.status == "pass":
print(f"✓ ({result.duration:.1f}s)")
elif result.status == "skip":
print(f"⊘ SKIP: {result.reason}")
else:
print(f"✗ FAIL: {result.reason}")
return results
def print_summary(results: List[TestResult]):
"""Print test summary."""
passed = sum(1 for r in results if r.status == "pass")
failed = sum(1 for r in results if r.status == "fail")
skipped = sum(1 for r in results if r.status == "skip")
print("\n" + "=" * 60)
print("SUMMARY")
print("=" * 60)
print(f" Passed: {passed}")
print(f" Failed: {failed}")
print(f" Skipped: {skipped}")
print(f" Total: {len(results)}")
if failed > 0:
print("\nFailed recipes:")
for r in results:
if r.status == "fail":
print(f" - {r.recipe}: {r.reason}")
return failed == 0
def main():
"""Main entry point."""
import argparse
parser = argparse.ArgumentParser(description="Run all Agent-Recipes tests")
parser.add_argument("--full", action="store_true", help="Run full tests (not just dry-run)")
parser.add_argument("--recipe", help="Run specific recipe only")
parser.add_argument("--json", action="store_true", help="Output JSON results")
args = parser.parse_args()
if args.recipe:
results = [run_recipe_dry_run(args.recipe)]
else:
results = run_all_recipes(dry_run_only=not args.full)
if args.json:
output = [{"recipe": r.recipe, "status": r.status, "reason": r.reason} for r in results]
print(json.dumps(output, indent=2))
else:
success = print_summary(results)
sys.exit(0 if success else 1)
if __name__ == "__main__":
main()
+71
View File
@@ -0,0 +1,71 @@
# Recipe Registry Example
This example demonstrates how to use the PraisonAI recipe registry for publishing and pulling recipes via both local filesystem and HTTP server.
## Features Demonstrated
- Creating a local registry
- Starting an HTTP registry server
- Publishing recipes with token authentication
- Listing and searching recipes
- Pulling recipes from HTTP registry
## Quick Start
```bash
# Run the HTTP registry example
python http_registry_example.py
```
## HTTP Registry Server
```bash
# Start HTTP registry server
praisonai registry serve --port 7777
# Start with authentication
praisonai registry serve --port 7777 --token mysecret
# Check server status
praisonai registry status --registry http://localhost:7777
```
## CLI Commands with HTTP Registry
```bash
# Publish to HTTP registry
praisonai recipe publish ./my-recipe --registry http://localhost:7777 --json
# Publish with token
praisonai recipe publish ./my-recipe --registry http://localhost:7777 --token mysecret
# Pull from HTTP registry
praisonai recipe pull [email protected] --registry http://localhost:7777 -o ./recipes
# List recipes from HTTP registry
praisonai recipe list --registry http://localhost:7777 --json
# Search HTTP registry
praisonai recipe search "hello" --registry http://localhost:7777
```
## Local Registry Commands
```bash
# Publish to local registry (default)
praisonai recipe publish ./my-recipe --json
# Pull from local registry
praisonai recipe pull [email protected] -o ./recipes
# Use custom local path
praisonai recipe publish ./my-recipe --registry /path/to/registry
```
## Environment Variables
- `PRAISONAI_REGISTRY_TOKEN` - Default token for HTTP registry authentication
## Default Registry Location
By default, the local registry is stored at `~/.praison/registry`.
+230
View File
@@ -0,0 +1,230 @@
#!/usr/bin/env python3
"""
HTTP Recipe Registry Example
This example demonstrates:
1. Starting an HTTP registry server programmatically
2. Publishing recipes with token authentication
3. Listing and searching recipes via HTTP
4. Pulling recipes from HTTP registry
Requirements:
- praisonai installed
- No external API keys required (local registry only)
Environment Variables (optional):
- PRAISONAI_REGISTRY_TOKEN: Token for authentication
"""
import sys
import json
import time
import shutil
import tarfile
import tempfile
import subprocess
from pathlib import Path
def create_sample_recipe(output_dir: Path) -> Path:
"""Create a sample recipe for testing."""
recipe_dir = output_dir / "sample-agent"
recipe_dir.mkdir(parents=True, exist_ok=True)
# Create manifest.json
manifest = {
"name": "sample-agent",
"version": "1.0.0",
"description": "A sample agent recipe for registry testing",
"tags": ["sample", "agent", "test"],
"author": "praison",
"files": ["recipe.yaml"]
}
(recipe_dir / "manifest.json").write_text(json.dumps(manifest, indent=2))
# Create recipe.yaml
recipe_yaml = """
name: sample-agent
version: "1.0.0"
description: A sample agent recipe
agents:
- name: assistant
role: General Assistant
goal: Help users with their questions
instructions: You are a helpful assistant.
tasks:
- name: respond
description: Respond to user query
agent: assistant
"""
(recipe_dir / "recipe.yaml").write_text(recipe_yaml.strip())
# Pack into .praison bundle
bundle_path = output_dir / "sample-agent-1.0.0.praison"
with tarfile.open(bundle_path, "w:gz") as tar:
for file in recipe_dir.iterdir():
tar.add(file, arcname=file.name)
return bundle_path
def start_registry_server(port: int, registry_path: Path, token: str = None):
"""Start registry server in background process."""
cmd = [
sys.executable, "-c",
f"""
import sys
sys.path.insert(0, '/Users/praison/praisonai-package/src/praisonai')
from praisonai.recipe.server import create_wsgi_app
from wsgiref.simple_server import make_server, WSGIRequestHandler
from pathlib import Path
class QuietHandler(WSGIRequestHandler):
def log_message(self, format, *args):
pass
app = create_wsgi_app(registry_path=Path("{registry_path}"), token={repr(token)})
server = make_server("127.0.0.1", {port}, app, handler_class=QuietHandler)
server.serve_forever()
"""
]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return proc
def main():
print("=" * 60)
print("HTTP Recipe Registry Example")
print("=" * 60)
# Setup
work_dir = Path(tempfile.mkdtemp(prefix="registry_example_"))
registry_path = work_dir / "registry"
pulled_dir = work_dir / "pulled"
port = 7799
token = "example-secret-token"
print(f"\nWork directory: {work_dir}")
print(f"Registry path: {registry_path}")
print(f"Server port: {port}")
print(f"Token: {'*' * len(token)} (redacted)")
try:
# 1. Create sample recipe
print("\n[1] Creating sample recipe...")
bundle_path = create_sample_recipe(work_dir)
print(f" ✓ Created bundle: {bundle_path.name}")
# 2. Start HTTP registry server
print("\n[2] Starting HTTP registry server...")
server = start_registry_server(port, registry_path, token)
time.sleep(1) # Wait for server to start
print(f" ✓ Server running on http://127.0.0.1:{port}")
# 3. Check health
print("\n[3] Checking server health...")
result = subprocess.run(
["curl", "-s", f"http://127.0.0.1:{port}/healthz"],
capture_output=True, text=True
)
health = json.loads(result.stdout)
print(f" Status: {health['status']}")
print(f" Auth required: {health['auth_required']}")
# 4. Publish WITHOUT token (should fail)
print("\n[4] Publishing WITHOUT token (expect failure)...")
result = subprocess.run(
["python3", "-m", "praisonai", "recipe", "publish", str(bundle_path),
"--registry", f"http://127.0.0.1:{port}", "--json"],
capture_output=True, text=True,
cwd="/Users/praison/praisonai-package/src/praisonai"
)
if result.returncode != 0 or "error" in result.stdout.lower() or "401" in result.stdout:
print(" ✓ Correctly rejected (authentication required)")
else:
print(f" ✗ Unexpected success: {result.stdout}")
# 5. Publish WITH token (should succeed)
print("\n[5] Publishing WITH token...")
result = subprocess.run(
["python3", "-m", "praisonai", "recipe", "publish", str(bundle_path),
"--registry", f"http://127.0.0.1:{port}", "--token", token, "--json"],
capture_output=True, text=True,
cwd="/Users/praison/praisonai-package/src/praisonai"
)
try:
data = json.loads(result.stdout)
if data.get("ok"):
print(f" ✓ Published: {data['name']}@{data['version']}")
else:
print(f" ✗ Failed: {result.stdout}")
return 1
except json.JSONDecodeError:
print(f" Output: {result.stdout}")
print(f" Stderr: {result.stderr}")
return 1
# 6. List recipes
print("\n[6] Listing recipes from registry...")
result = subprocess.run(
["python3", "-m", "praisonai", "recipe", "list",
"--registry", f"http://127.0.0.1:{port}", "--json"],
capture_output=True, text=True,
cwd="/Users/praison/praisonai-package/src/praisonai"
)
recipes = json.loads(result.stdout)
print(f" Found {len(recipes)} recipe(s):")
for r in recipes:
print(f" - {r['name']} v{r['version']}: {r.get('description', '')[:40]}")
# 7. Search recipes
print("\n[7] Searching for 'agent'...")
result = subprocess.run(
["python3", "-m", "praisonai", "recipe", "search", "agent",
"--registry", f"http://127.0.0.1:{port}", "--json"],
capture_output=True, text=True,
cwd="/Users/praison/praisonai-package/src/praisonai"
)
matches = json.loads(result.stdout)
print(f" Found {len(matches)} match(es)")
# 8. Pull recipe
print("\n[8] Pulling recipe...")
pulled_dir.mkdir(parents=True, exist_ok=True)
result = subprocess.run(
["python3", "-m", "praisonai", "recipe", "pull", "sample-agent",
"--registry", f"http://127.0.0.1:{port}", "-o", str(pulled_dir), "--json"],
capture_output=True, text=True,
cwd="/Users/praison/praisonai-package/src/praisonai"
)
data = json.loads(result.stdout)
if data.get("ok"):
print(f" ✓ Pulled to: {data['path']}")
# Verify content
manifest_path = Path(data['path']) / "manifest.json"
if manifest_path.exists():
manifest = json.loads(manifest_path.read_text())
print(f" ✓ Verified: {manifest['name']}@{manifest['version']}")
else:
print(f" ✗ Failed: {result.stdout}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
# Cleanup
server.terminate()
server.wait()
finally:
# Clean up temp directory
shutil.rmtree(work_dir, ignore_errors=True)
return 0
if __name__ == "__main__":
sys.exit(main())
+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""
PraisonAI Recipe Registry Example
This example demonstrates how to:
1. Create and publish recipes to a local registry
2. Search and list recipes
3. Pull recipes from the registry
Prerequisites:
- pip install praisonai
Usage:
python registry_example.py
"""
import json
import tarfile
import tempfile
from pathlib import Path
def create_sample_recipe(tmp_dir: Path) -> Path:
"""Create a sample recipe for demonstration."""
recipe_dir = tmp_dir / "hello-world"
recipe_dir.mkdir(parents=True, exist_ok=True)
# Create TEMPLATE.yaml
template_content = """
name: hello-world
version: "1.0.0"
description: A simple hello world recipe
author: example
tags:
- demo
- hello
- example
requires:
env:
- OPENAI_API_KEY
config:
input:
name:
type: string
required: true
description: Name to greet
"""
with open(recipe_dir / "TEMPLATE.yaml", "w") as f:
f.write(template_content.strip())
# Create main.py
main_content = """
def greet(name: str) -> str:
return f"Hello, {name}!"
if __name__ == "__main__":
print(greet("World"))
"""
with open(recipe_dir / "main.py", "w") as f:
f.write(main_content.strip())
return recipe_dir
def pack_recipe(recipe_dir: Path, output_path: Path) -> Path:
"""Pack a recipe into a .praison bundle."""
import hashlib
import io
from datetime import datetime, timezone
with tarfile.open(output_path, "w:gz") as tar:
manifest = {
"name": "hello-world",
"version": "1.0.0",
"description": "A simple hello world recipe",
"tags": ["demo", "hello", "example"],
"created_at": datetime.now(timezone.utc).isoformat(),
"files": [],
}
for file_path in recipe_dir.rglob("*"):
if file_path.is_file() and not file_path.name.startswith("."):
rel_path = file_path.relative_to(recipe_dir)
tar.add(file_path, arcname=str(rel_path))
with open(file_path, "rb") as f:
checksum = hashlib.sha256(f.read()).hexdigest()
manifest["files"].append({
"path": str(rel_path),
"checksum": checksum,
})
manifest_bytes = json.dumps(manifest, indent=2).encode()
manifest_info = tarfile.TarInfo(name="manifest.json")
manifest_info.size = len(manifest_bytes)
tar.addfile(manifest_info, io.BytesIO(manifest_bytes))
return output_path
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Recipe Registry Example")
print("=" * 60)
# Use a temporary directory for the example
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
# Create registry in temp directory
registry_path = tmp_path / "registry"
print("\n1. Creating local registry...")
from praisonai.recipe.registry import LocalRegistry
registry = LocalRegistry(registry_path)
print(f" Registry created at: {registry_path}")
# Create and pack a sample recipe
print("\n2. Creating sample recipe...")
recipe_dir = create_sample_recipe(tmp_path)
print(f" Recipe created at: {recipe_dir}")
print("\n3. Packing recipe into bundle...")
bundle_path = tmp_path / "hello-world-1.0.0.praison"
pack_recipe(recipe_dir, bundle_path)
print(f" Bundle created: {bundle_path}")
# Publish to registry
print("\n4. Publishing to registry...")
result = registry.publish(bundle_path)
print(f" Published: {result['name']}@{result['version']}")
print(f" Checksum: {result['checksum'][:16]}...")
# List recipes
print("\n5. Listing recipes in registry...")
recipes = registry.list_recipes()
for r in recipes:
print(f" - {r['name']} ({r['version']}): {r['description']}")
# Search recipes
print("\n6. Searching for 'hello'...")
results = registry.search("hello")
print(f" Found {len(results)} recipe(s)")
# Get versions
print("\n7. Getting versions of 'hello-world'...")
versions = registry.get_versions("hello-world")
print(f" Versions: {versions}")
# Pull recipe
print("\n8. Pulling recipe from registry...")
output_dir = tmp_path / "pulled"
pull_result = registry.pull("hello-world", output_dir=output_dir)
print(f" Pulled to: {pull_result['path']}")
# Verify pulled files
print("\n9. Verifying pulled files...")
pulled_recipe = output_dir / "hello-world"
for f in pulled_recipe.iterdir():
print(f" - {f.name}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+43
View File
@@ -0,0 +1,43 @@
# Run History Example
This example demonstrates how to use PraisonAI run history for storing, querying, and exporting recipe runs.
## Features Demonstrated
- Storing run results with input/output data
- Listing and filtering runs
- Querying run details
- Exporting runs for replay/debugging
- Storage statistics and cleanup
## Quick Start
```bash
python run_history_example.py
```
## CLI Commands
```bash
# List recent runs
praisonai recipe runs list
# List runs for a specific recipe
praisonai recipe runs list --recipe support-reply
# Get storage stats
praisonai recipe runs stats
# Export a run
praisonai recipe export run-abc123 -o export.json
# Replay a run
praisonai recipe replay export.json --compare
# Cleanup old runs
praisonai recipe runs cleanup
```
## Default Storage Location
Run history is stored at `~/.praison/runs`.
+149
View File
@@ -0,0 +1,149 @@
#!/usr/bin/env python3
"""
PraisonAI Run History Example
This example demonstrates how to:
1. Store recipe run results in history
2. List and query run history
3. Export runs for replay/debugging
Prerequisites:
- pip install praisonai
Usage:
python run_history_example.py
"""
import tempfile
from pathlib import Path
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Run History Example")
print("=" * 60)
# Use a temporary directory for the example
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
# Create history storage in temp directory
history_path = tmp_path / "runs"
print("\n1. Creating run history storage...")
from praisonai.recipe.history import RunHistory
from praisonai.recipe.models import RecipeResult, RecipeStatus
history = RunHistory(history_path)
print(f" Storage created at: {history_path}")
# Create sample run results
print("\n2. Storing sample run results...")
# Run 1: Successful run
result1 = RecipeResult(
run_id="run-abc123",
recipe="support-reply",
version="1.0.0",
status=RecipeStatus.SUCCESS,
output={"reply": "Thank you for contacting us..."},
metrics={"duration_sec": 2.5, "tokens": 150},
trace={"session_id": "session-001", "trace_id": "trace-xyz"},
)
history.store(
result=result1,
input_data={"ticket_id": "T-123", "message": "I need help"},
)
print(f" Stored: {result1.run_id} (success)")
# Run 2: Failed run
result2 = RecipeResult(
run_id="run-def456",
recipe="code-review",
version="2.0.0",
status=RecipeStatus.FAILED,
error="Timeout exceeded",
metrics={"duration_sec": 30.0},
trace={"session_id": "session-002"},
)
history.store(
result=result2,
input_data={"code": "def hello(): pass"},
)
print(f" Stored: {result2.run_id} (failed)")
# Run 3: Another successful run
result3 = RecipeResult(
run_id="run-ghi789",
recipe="support-reply",
version="1.0.0",
status=RecipeStatus.SUCCESS,
output={"reply": "Your issue has been resolved..."},
metrics={"duration_sec": 1.8},
trace={"session_id": "session-001"},
)
history.store(
result=result3,
input_data={"ticket_id": "T-456"},
)
print(f" Stored: {result3.run_id} (success)")
# List all runs
print("\n3. Listing all runs...")
runs = history.list_runs()
for run in runs:
status_icon = "✓" if run["status"] == "success" else "✗"
print(f" {status_icon} {run['run_id']} - {run['recipe']} ({run['status']})")
# Filter by recipe
print("\n4. Filtering runs by recipe 'support-reply'...")
filtered = history.list_runs(recipe="support-reply")
print(f" Found {len(filtered)} run(s)")
# Filter by session
print("\n5. Filtering runs by session 'session-001'...")
filtered = history.list_runs(session_id="session-001")
print(f" Found {len(filtered)} run(s)")
# Get specific run details
print("\n6. Getting details for run-abc123...")
run_data = history.get("run-abc123")
print(f" Recipe: {run_data['recipe']}")
print(f" Status: {run_data['status']}")
print(f" Input: {run_data.get('input', {})}")
print(f" Output: {run_data.get('output', {})}")
# Export a run
print("\n7. Exporting run-abc123...")
export_path = history.export("run-abc123", tmp_path / "export.json")
print(f" Exported to: {export_path}")
# Show export contents
import json
with open(export_path) as f:
export_data = json.load(f)
print(f" Format: {export_data['format']}")
print(f" Exported at: {export_data['exported_at']}")
# Get storage stats
print("\n8. Getting storage statistics...")
stats = history.get_stats()
print(f" Total runs: {stats['total_runs']}")
print(f" Storage size: {stats['total_size_bytes']} bytes")
# Cleanup old runs
print("\n9. Running cleanup...")
deleted = history.cleanup(retention_days=0) # Delete all for demo
print(f" Deleted {deleted} run(s)")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+60
View File
@@ -0,0 +1,60 @@
# Security Features Example
This example demonstrates PraisonAI security features including SBOM generation, lockfile validation, dependency auditing, and PII redaction.
## Features Demonstrated
- **SBOM Generation**: Generate Software Bill of Materials in CycloneDX or SPDX format
- **Lockfile Validation**: Validate presence and format of dependency lockfiles
- **Dependency Auditing**: Audit dependencies for vulnerabilities
- **PII Redaction**: Detect and redact personally identifiable information
## Quick Start
```bash
python security_example.py
```
## CLI Commands
### SBOM Generation
```bash
# Generate CycloneDX SBOM
praisonai recipe sbom ./my-recipe --format cyclonedx -o sbom.json
# Generate SPDX SBOM
praisonai recipe sbom ./my-recipe --format spdx -o sbom.json
```
### Dependency Auditing
```bash
# Audit dependencies
praisonai recipe audit ./my-recipe
# Strict audit (fail on issues)
praisonai recipe audit ./my-recipe --strict
```
### Lockfile Validation
```bash
# Validate recipe (includes lockfile check)
praisonai recipe validate ./my-recipe --require-lockfile
```
## PII Redaction Configuration
In your `TEMPLATE.yaml`:
```yaml
data_policy:
pii:
mode: redact # allow, deny, or redact
fields:
- email
- phone
- ssn
- credit_card
```
+188
View File
@@ -0,0 +1,188 @@
#!/usr/bin/env python3
"""
PraisonAI Security Features Example
This example demonstrates:
1. SBOM (Software Bill of Materials) generation
2. Lockfile validation
3. Dependency auditing
4. PII redaction
Prerequisites:
- pip install praisonai
Usage:
python security_example.py
"""
import json
import tempfile
from pathlib import Path
def create_sample_recipe(tmp_dir: Path) -> Path:
"""Create a sample recipe with dependencies."""
recipe_dir = tmp_dir / "secure-recipe"
recipe_dir.mkdir(parents=True, exist_ok=True)
# Create TEMPLATE.yaml
import yaml
template = {
"name": "secure-recipe",
"version": "1.0.0",
"description": "A recipe with security features",
"requires": {
"tools": ["web_search", "file_reader"],
"external": ["ffmpeg"],
"env": ["OPENAI_API_KEY"],
},
}
with open(recipe_dir / "TEMPLATE.yaml", "w") as f:
yaml.dump(template, f)
# Create lock directory with requirements
lock_dir = recipe_dir / "lock"
lock_dir.mkdir()
with open(lock_dir / "requirements.lock", "w") as f:
f.write("openai==1.0.0\n")
f.write("requests==2.31.0\n")
f.write("pydantic==2.0.0\n")
return recipe_dir
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Security Features Example")
print("=" * 60)
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)
# Create sample recipe
print("\n1. Creating sample recipe with dependencies...")
recipe_dir = create_sample_recipe(tmp_path)
print(f" Recipe created at: {recipe_dir}")
# =====================================================
# SBOM Generation
# =====================================================
print("\n" + "=" * 40)
print("SBOM Generation")
print("=" * 40)
from praisonai.recipe.security import generate_sbom
print("\n2. Generating CycloneDX SBOM...")
sbom = generate_sbom(recipe_dir, format="cyclonedx")
print(f" Format: {sbom['bomFormat']}")
print(f" Spec Version: {sbom['specVersion']}")
print(f" Components: {len(sbom['components'])}")
print("\n Components:")
for comp in sbom["components"][:5]:
print(f" - {comp['name']}@{comp['version']} ({comp['type']})")
# Save SBOM
sbom_path = tmp_path / "sbom.json"
with open(sbom_path, "w") as f:
json.dump(sbom, f, indent=2)
print(f"\n SBOM saved to: {sbom_path}")
# =====================================================
# Lockfile Validation
# =====================================================
print("\n" + "=" * 40)
print("Lockfile Validation")
print("=" * 40)
from praisonai.recipe.security import validate_lockfile
print("\n3. Validating lockfile...")
result = validate_lockfile(recipe_dir)
print(f" Valid: {result['valid']}")
print(f" Lockfile: {result['lockfile']}")
print(f" Type: {result['lockfile_type']}")
# Test strict validation without lockfile
print("\n4. Testing strict validation on recipe without lockfile...")
no_lock_dir = tmp_path / "no-lock-recipe"
no_lock_dir.mkdir()
result = validate_lockfile(no_lock_dir, strict=True)
print(f" Valid: {result['valid']}")
print(f" Errors: {result['errors']}")
# =====================================================
# Dependency Auditing
# =====================================================
print("\n" + "=" * 40)
print("Dependency Auditing")
print("=" * 40)
from praisonai.recipe.security import audit_dependencies
print("\n5. Auditing dependencies...")
report = audit_dependencies(recipe_dir)
print(f" Recipe: {report['recipe']}")
print(f" Lockfile: {report['lockfile']}")
print(f" Dependencies: {len(report['dependencies'])}")
print(f" Vulnerabilities: {len(report['vulnerabilities'])}")
print(f" Warnings: {len(report['warnings'])}")
print(f" Passed: {report['passed']}")
if report["warnings"]:
print("\n Warnings:")
for warn in report["warnings"]:
print(f" - {warn}")
# =====================================================
# PII Redaction
# =====================================================
print("\n" + "=" * 40)
print("PII Redaction")
print("=" * 40)
from praisonai.recipe.security import redact_pii, detect_pii
# Sample data with PII
sample_data = {
"customer": {
"name": "John Doe",
"email": "[email protected]",
"phone": "555-123-4567",
"message": "Please contact me at [email protected]",
},
"ticket_id": "T-12345",
}
print("\n6. Detecting PII in sample data...")
detections = detect_pii(sample_data)
print(f" Found {len(detections)} PII instance(s):")
for d in detections:
print(f" - {d['type']} at {d['path']}")
print("\n7. Redacting PII...")
policy = {
"pii": {
"mode": "redact",
"fields": ["email", "phone"],
}
}
redacted = redact_pii(sample_data, policy)
print(" Original email:", sample_data["customer"]["email"])
print(" Redacted email:", redacted["customer"]["email"])
print(" Original phone:", sample_data["customer"]["phone"])
print(" Redacted phone:", redacted["customer"]["phone"])
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+142
View File
@@ -0,0 +1,142 @@
# PraisonAI Serve Examples
Examples for all PraisonAI server types and the unified endpoints CLI.
## Examples
| Example | Description | CLI Command |
|---------|-------------|-------------|
| `unified_server.py` | All providers in one server | `praisonai serve unified` |
| `agent_as_api_single.py` | Single agent HTTP API | `praisonai serve agents` |
| `agents_as_api_router.py` | Multi-agent router API | `praisonai serve agents` |
| `a2a_server_client.py` | A2A protocol server | `praisonai serve a2a` |
| `a2u_events_stream.py` | A2U event stream | `praisonai serve a2u` |
| `mcp_http_server.py` | MCP HTTP server | `praisonai serve mcp` |
| `tools_as_mcp_server.py` | Tools as MCP server | `praisonai serve tools` |
| `agent_launch_modes.py` | Agent.launch() API | Python only |
| `endpoints_unified_client.py` | Unified client | `praisonai endpoints` |
| `serve_example.py` | Recipe server client | `praisonai recipe serve` |
## Server Commands
| Command | Description |
|---------|-------------|
| `praisonai serve unified --port 8765` | Start unified server |
| `praisonai serve agents --file agents.yaml --port 8000` | Start agents API |
| `praisonai serve recipe --port 8765` | Start recipe server |
| `praisonai serve mcp --transport http --port 8080` | Start MCP server |
| `praisonai serve tools --port 8081` | Start tools MCP server |
| `praisonai serve a2a --port 8082` | Start A2A server |
| `praisonai serve a2u --port 8083` | Start A2U server |
## Client Commands
| Command | Description |
|---------|-------------|
| `praisonai endpoints list` | List all endpoints |
| `praisonai endpoints list --type agents-api` | Filter by type |
| `praisonai endpoints describe <name>` | Get endpoint details |
| `praisonai endpoints invoke <name> --input-json '{}'` | Invoke endpoint |
| `praisonai endpoints health` | Check server health |
| `praisonai endpoints types` | List provider types |
| `praisonai endpoints discovery` | Show discovery document |
## Quick Start
```bash
# Terminal 1: Start unified server
export OPENAI_API_KEY=your-key
praisonai serve unified --port 8765
# Terminal 2: Use endpoints CLI
praisonai endpoints health
praisonai endpoints list
praisonai endpoints types
```
## Provider Types
| Type | Description |
|------|-------------|
| `recipe` | Recipe runner endpoints |
| `agents-api` | Single/multi-agent HTTP API |
| `mcp` | MCP server (stdio, http, sse) |
| `tools-mcp` | Tools exposed as MCP server |
| `a2a` | Agent-to-agent protocol |
| `a2u` | Agent-to-user event stream |
## Configuration Options
| Option | Description | Default |
|--------|-------------|---------|
| `host` | Server bind address | 127.0.0.1 |
| `port` | Server port | 8765 |
| `auth` | Auth type (none, api-key, jwt) | none |
| `api_key` | API key for auth | - |
| `preload` | Preload recipes on startup | false |
| `recipes` | List of recipes to serve | all |
| `cors_origins` | CORS allowed origins | - |
## Advanced Features
| Feature | CLI Flag | Description | Docs |
|---------|----------|-------------|------|
| Rate Limiting | `--rate_limit 100` | Requests per minute per client | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
| Request Size Limit | `--max_request_size 10485760` | Max request body (bytes) | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
| Metrics Endpoint | `--enable_metrics` | Prometheus /metrics endpoint | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
| Admin Reload | `--enable_admin` | Hot reload /admin/reload | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
| Workers | `--workers 4` | Multi-process workers | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
| OpenTelemetry | `--trace_exporter otlp` | Distributed tracing | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
| OpenAPI | `GET /openapi.json` | API specification | [Code](/docs/features/recipe-serve-advanced) [CLI](/docs/cli/recipe-serve-advanced) |
## Advanced Examples
| Example | Description |
|---------|-------------|
| `recipe_serve_features.py` | All advanced features demo |
## Advanced CLI Commands
```bash
# Production server with all features
praisonai recipe serve \
--host 0.0.0.0 \
--port 8765 \
--auth api-key \
--workers 4 \
--rate_limit 100 \
--enable_metrics \
--enable_admin
# Get metrics
curl http://localhost:8765/metrics
# Get OpenAPI spec
curl http://localhost:8765/openapi.json
# Hot reload recipes
curl -X POST http://localhost:8765/admin/reload \
-H "X-API-Key: your-key"
```
## CLI Commands
```bash
# Health check
praisonai endpoints health
# List recipes (with auth)
praisonai endpoints list --api-key your-key
# Invoke recipe
praisonai endpoints invoke my-recipe \
--input-json '{"query": "Hello"}' \
--api-key your-key \
--json
```
## Security Notes
- Always use `--auth api-key` when binding to `0.0.0.0`
- Store API keys in environment variables, not config files
- Use HTTPS in production (via reverse proxy)
+190
View File
@@ -0,0 +1,190 @@
#!/usr/bin/env python3
"""
A2A (Agent-to-Agent) Server and Client Example
Demonstrates:
- Launching an agent as A2A server
- Agent card discovery
- Sending A2A messages
- JSON-RPC protocol
Usage:
# Run this example (starts server)
python a2a_server_client.py
# Or use CLI:
praisonai serve a2a --port 8082
# Test with curl:
curl http://localhost:8082/.well-known/agent.json
curl -X POST http://localhost:8082/a2a \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"message/send","id":"1","params":{"message":{"role":"user","parts":[{"type":"text","text":"Hello!"}]}}}'
"""
import os
import sys
import json
import threading
import time
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
sys.exit(1)
def run_server():
"""Run A2A server."""
try:
from praisonaiagents import Agent
from praisonaiagents.ui.a2a import A2A
from fastapi import FastAPI
import uvicorn
except ImportError as e:
print(f"Error: Missing dependency - {e}")
print("Install with: pip install 'praisonaiagents[api]'")
sys.exit(1)
# Create agent
agent = Agent(
name="A2A-Assistant",
role="Helpful AI Assistant",
goal="Help other agents and users with their questions",
backstory="You are a knowledgeable assistant accessible via A2A protocol.",
llm="gpt-4o-mini"
)
# Create A2A interface
a2a = A2A(
agent=agent,
url="http://localhost:8082/a2a",
name="A2A-Assistant",
description="A helpful AI assistant accessible via A2A protocol"
)
# Create FastAPI app
app = FastAPI(title="PraisonAI A2A Server")
app.include_router(a2a.get_router())
# Add discovery endpoint
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-a2a",
"providers": [{"type": "a2a", "name": "A2A Protocol", "capabilities": ["agent-card", "message-send"]}],
"endpoints": [{"name": "a2a", "provider_type": "a2a", "streaming": ["sse"]}]
}
@app.get("/")
async def root():
return {
"message": "PraisonAI A2A Server",
"agent_card": "/.well-known/agent.json",
"a2a_endpoint": "/a2a",
"discovery": "/__praisonai__/discovery"
}
print("Starting A2A server on http://localhost:8082")
print("Agent Card: http://localhost:8082/.well-known/agent.json")
print("A2A Endpoint: http://localhost:8082/a2a")
uvicorn.run(app, host="127.0.0.1", port=8082, log_level="warning")
def run_client():
"""Run A2A client test."""
import urllib.request
import urllib.error
base_url = "http://localhost:8082"
print("\n--- A2A Client Test ---")
# 1. Get agent card
print("\n1. Getting Agent Card...")
try:
req = urllib.request.Request(f"{base_url}/.well-known/agent.json")
with urllib.request.urlopen(req, timeout=5) as resp:
agent_card = json.loads(resp.read().decode())
print(f" Agent: {agent_card.get('name')}")
print(f" URL: {agent_card.get('url')}")
print(f" Capabilities: {agent_card.get('capabilities', {})}")
except Exception as e:
print(f" Error: {e}")
return
# 2. Send A2A message
print("\n2. Sending A2A Message...")
message = {
"jsonrpc": "2.0",
"method": "message/send",
"id": "test-1",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Hello! What can you help me with?"}]
}
}
}
try:
req = urllib.request.Request(
f"{base_url}/a2a",
data=json.dumps(message).encode(),
headers={"Content-Type": "application/json"},
method="POST"
)
with urllib.request.urlopen(req, timeout=30) as resp:
response = json.loads(resp.read().decode())
if "result" in response:
result_msg = response["result"].get("message", {})
parts = result_msg.get("parts", [])
for part in parts:
if part.get("type") == "text":
print(f" Response: {part.get('text', '')[:200]}...")
elif "error" in response:
print(f" Error: {response['error']}")
except Exception as e:
print(f" Error: {e}")
# 3. Check discovery
print("\n3. Checking Discovery...")
try:
req = urllib.request.Request(f"{base_url}/__praisonai__/discovery")
with urllib.request.urlopen(req, timeout=5) as resp:
discovery = json.loads(resp.read().decode())
print(f" Server: {discovery.get('server_name')}")
print(f" Providers: {[p.get('type') for p in discovery.get('providers', [])]}")
except Exception as e:
print(f" Error: {e}")
print("\n✓ A2A client test completed!")
def main():
print("=" * 60)
print("A2A (Agent-to-Agent) Server and Client Example")
print("=" * 60)
mode = sys.argv[1] if len(sys.argv) > 1 else "server"
if mode == "client":
run_client()
elif mode == "test":
# Start server in background, run client, then stop
print("Starting server in background...")
server_thread = threading.Thread(target=run_server, daemon=True)
server_thread.start()
time.sleep(3) # Wait for server to start
run_client()
else:
print("\nStarting A2A server...")
print("Press Ctrl+C to stop")
print("\nTo test, run in another terminal:")
print(" python a2a_server_client.py client")
run_server()
if __name__ == "__main__":
main()
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""
A2U (Agent-to-User) Event Stream Example
Demonstrates:
- Launching an A2U event stream server
- Subscribing to agent events
- SSE (Server-Sent Events) streaming
- Event filtering
Usage:
# Run this example (starts server)
python a2u_events_stream.py
# Or use CLI:
praisonai serve a2u --port 8083
# Test with curl:
curl http://localhost:8083/a2u/info
curl -N http://localhost:8083/a2u/events/events
"""
import os
import sys
import json
import threading
import time
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
sys.exit(1)
def run_server():
"""Run A2U server."""
try:
from fastapi import FastAPI
import uvicorn
from praisonai.endpoints.a2u_server import (
create_a2u_routes,
emit_agent_started,
emit_agent_thinking,
emit_agent_response,
emit_agent_completed,
)
except ImportError as e:
print(f"Error: Missing dependency - {e}")
print("Install with: pip install praisonai[serve]")
sys.exit(1)
app = FastAPI(title="PraisonAI A2U Server")
# Add A2U routes
create_a2u_routes(app)
# Add discovery endpoint
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-a2u",
"providers": [{"type": "a2u", "name": "A2U Event Stream", "capabilities": ["subscribe", "stream"]}],
"endpoints": [{"name": "events", "provider_type": "a2u", "streaming": ["sse"]}]
}
@app.get("/")
async def root():
return {
"message": "PraisonAI A2U Server",
"info": "/a2u/info",
"events": "/a2u/events/<stream>",
"discovery": "/__praisonai__/discovery"
}
# Demo endpoint to emit events
@app.post("/demo/emit")
async def demo_emit():
"""Emit demo events for testing."""
agent_id = "demo-agent-1"
emit_agent_started(agent_id, "DemoAgent")
emit_agent_thinking(agent_id, "Processing your request...")
emit_agent_response(agent_id, "Here is my response to your query.")
emit_agent_completed(agent_id, {"status": "success"})
return {"message": "Demo events emitted", "agent_id": agent_id}
print("Starting A2U server on http://localhost:8083")
print("Info: http://localhost:8083/a2u/info")
print("Events: http://localhost:8083/a2u/events/events")
print("Demo: POST http://localhost:8083/demo/emit")
uvicorn.run(app, host="127.0.0.1", port=8083, log_level="warning")
def run_client():
"""Run A2U client test."""
import urllib.request
import urllib.error
base_url = "http://localhost:8083"
print("\n--- A2U Client Test ---")
# 1. Get A2U info
print("\n1. Getting A2U Info...")
try:
req = urllib.request.Request(f"{base_url}/a2u/info")
with urllib.request.urlopen(req, timeout=5) as resp:
info = json.loads(resp.read().decode())
print(f" Name: {info.get('name')}")
print(f" Version: {info.get('version')}")
print(f" Streams: {info.get('streams')}")
print(f" Event Types: {info.get('event_types')}")
except Exception as e:
print(f" Error: {e}")
return
# 2. Subscribe to events
print("\n2. Subscribing to Events...")
try:
req = urllib.request.Request(
f"{base_url}/a2u/subscribe",
data=json.dumps({"stream": "events", "filters": []}).encode(),
headers={"Content-Type": "application/json"},
method="POST"
)
with urllib.request.urlopen(req, timeout=5) as resp:
sub = json.loads(resp.read().decode())
print(f" Subscription ID: {sub.get('subscription_id')}")
print(f" Stream URL: {sub.get('stream_url')}")
except Exception as e:
print(f" Error: {e}")
# 3. Emit demo events
print("\n3. Emitting Demo Events...")
try:
req = urllib.request.Request(
f"{base_url}/demo/emit",
data=b"{}",
headers={"Content-Type": "application/json"},
method="POST"
)
with urllib.request.urlopen(req, timeout=5) as resp:
result = json.loads(resp.read().decode())
print(f" {result.get('message')}")
print(f" Agent ID: {result.get('agent_id')}")
except Exception as e:
print(f" Error: {e}")
# 4. Check discovery
print("\n4. Checking Discovery...")
try:
req = urllib.request.Request(f"{base_url}/__praisonai__/discovery")
with urllib.request.urlopen(req, timeout=5) as resp:
discovery = json.loads(resp.read().decode())
print(f" Server: {discovery.get('server_name')}")
print(f" Providers: {[p.get('type') for p in discovery.get('providers', [])]}")
except Exception as e:
print(f" Error: {e}")
print("\n✓ A2U client test completed!")
print("\nTo stream events, run:")
print(f" curl -N {base_url}/a2u/events/events")
def main():
print("=" * 60)
print("A2U (Agent-to-User) Event Stream Example")
print("=" * 60)
mode = sys.argv[1] if len(sys.argv) > 1 else "server"
if mode == "client":
run_client()
elif mode == "test":
print("Starting server in background...")
server_thread = threading.Thread(target=run_server, daemon=True)
server_thread.start()
time.sleep(2)
run_client()
else:
print("\nStarting A2U server...")
print("Press Ctrl+C to stop")
print("\nTo test, run in another terminal:")
print(" python a2u_events_stream.py client")
run_server()
if __name__ == "__main__":
main()
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env python3
"""
Single Agent as HTTP API Example
Demonstrates launching a single agent as an HTTP API server with:
- REST endpoint for queries
- Streaming support (SSE)
- Discovery endpoint
- Health check
Usage:
# Run this example
python agent_as_api_single.py
# Or use CLI:
praisonai serve agents --file agents.yaml --port 8000
# Test with curl:
curl -X POST http://localhost:8000/agent \
-H "Content-Type: application/json" \
-d '{"query": "What is AI?"}'
"""
import os
import sys
# Ensure API key is set
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
sys.exit(1)
def main():
print("=" * 60)
print("Single Agent as HTTP API Example")
print("=" * 60)
try:
from praisonaiagents import Agent
except ImportError:
print("Error: praisonaiagents not installed")
print("Install with: pip install praisonaiagents")
sys.exit(1)
# Create a single agent
agent = Agent(
name="Assistant",
role="Helpful AI Assistant",
goal="Help users with their questions accurately and concisely",
backstory="You are a knowledgeable assistant who provides clear, helpful answers.",
llm="gpt-4o-mini",
verbose=True
)
print(f"Agent: {agent.name}")
print(f"Role: {agent.role}")
# Launch as HTTP API
print("\nLaunching agent as HTTP API...")
print("Endpoints:")
print(" POST /agent - Query the agent")
print(" GET /health - Health check")
print(" GET /__praisonai__/discovery - Discovery document")
print("\nPress Ctrl+C to stop")
try:
# Use Agent.launch() to start HTTP server
agent.launch(
port=8000,
host="127.0.0.1",
path="/agent"
)
except KeyboardInterrupt:
print("\nServer stopped")
except Exception as e:
print(f"Error launching server: {e}")
# Fallback: manual FastAPI setup
print("\nFallback: Using manual FastAPI setup...")
launch_manual(agent)
def launch_manual(agent):
"""Manual FastAPI server setup as fallback."""
try:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn
except ImportError:
print("Error: FastAPI/uvicorn not installed")
print("Install with: pip install fastapi uvicorn")
return
app = FastAPI(title="PraisonAI Agent API")
@app.post("/agent")
async def query_agent(request: Request):
try:
body = await request.json()
query = body.get("query", "")
if not query:
return JSONResponse({"error": "query required"}, status_code=400)
response = agent.chat(query)
return {"response": response}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/health")
async def health():
return {"status": "healthy", "agent": agent.name}
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-agent",
"providers": [{"type": "agents-api", "name": "Single Agent API"}],
"endpoints": [{"name": "agent", "provider_type": "agents-api"}]
}
@app.get("/")
async def root():
return {
"message": f"PraisonAI Agent: {agent.name}",
"endpoints": ["/agent", "/health", "/__praisonai__/discovery"]
}
uvicorn.run(app, host="127.0.0.1", port=8000)
if __name__ == "__main__":
main()
+220
View File
@@ -0,0 +1,220 @@
#!/usr/bin/env python3
"""
Agent.launch() and Agents.launch() Example
Demonstrates the high-level Python API for launching servers:
- Agent.launch() for single agent
- Agents.launch() for multi-agent
- Different server modes (HTTP, MCP, A2A)
Usage:
# Run this example
python agent_launch_modes.py
# Test endpoints:
curl http://localhost:8000/agent
curl http://localhost:8000/health
"""
import os
import sys
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
sys.exit(1)
def demo_single_agent_launch():
"""Demo Agent.launch() for single agent."""
print("\n--- Single Agent Launch ---")
try:
from praisonaiagents import Agent
except ImportError:
print("Error: praisonaiagents not installed")
return False
agent = Agent(
name="Assistant",
role="Helpful AI Assistant",
goal="Help users with their questions",
llm="gpt-4o-mini"
)
print(f"Agent: {agent.name}")
print("Launching as HTTP API on port 8000...")
print("\nEndpoints:")
print(" POST /agent - Query the agent")
print(" GET /health - Health check")
print("\nPress Ctrl+C to stop")
try:
agent.launch(port=8000, host="127.0.0.1", path="/agent")
except AttributeError:
print("Agent.launch() not available, using fallback...")
launch_single_fallback(agent)
except KeyboardInterrupt:
print("\nStopped")
return True
def demo_multi_agent_launch():
"""Demo Agents.launch() for multi-agent."""
print("\n--- Multi-Agent Launch ---")
try:
from praisonaiagents import Agent, PraisonAIAgents
except ImportError:
print("Error: praisonaiagents not installed")
return False
researcher = Agent(
name="Researcher",
role="Research Specialist",
goal="Find accurate information",
llm="gpt-4o-mini"
)
writer = Agent(
name="Writer",
role="Content Writer",
goal="Create engaging content",
llm="gpt-4o-mini"
)
agents = PraisonAIAgents(agents=[researcher, writer])
print(f"Agents: {[researcher.name, writer.name]}")
print("Launching as HTTP API on port 8000...")
print("\nEndpoints:")
print(" POST /agents - Route to best agent")
print(" POST /agents/researcher - Query researcher")
print(" POST /agents/writer - Query writer")
print(" GET /agents/list - List agents")
print("\nPress Ctrl+C to stop")
try:
agents.launch(port=8000, host="127.0.0.1")
except AttributeError:
print("Agents.launch() not available, using fallback...")
launch_multi_fallback([researcher, writer])
except KeyboardInterrupt:
print("\nStopped")
return True
def launch_single_fallback(agent):
"""Fallback implementation for Agent.launch()."""
try:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn
except ImportError:
print("Error: FastAPI/uvicorn not installed")
return
app = FastAPI(title=f"PraisonAI Agent: {agent.name}")
@app.post("/agent")
async def query(request: Request):
try:
body = await request.json()
query_text = body.get("query", "")
response = agent.chat(query_text)
return {"response": response}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/health")
async def health():
return {"status": "healthy", "agent": agent.name}
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": f"praisonai-{agent.name.lower()}",
"providers": [{"type": "agents-api", "name": "Single Agent API"}],
"endpoints": [{"name": "agent", "provider_type": "agents-api"}]
}
uvicorn.run(app, host="127.0.0.1", port=8000)
def launch_multi_fallback(agents):
"""Fallback implementation for Agents.launch()."""
try:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn
except ImportError:
print("Error: FastAPI/uvicorn not installed")
return
app = FastAPI(title="PraisonAI Multi-Agent API")
agent_map = {a.name.lower(): a for a in agents}
@app.post("/agents")
async def route(request: Request):
try:
body = await request.json()
query_text = body.get("query", "")
# Simple routing
agent = agents[0]
response = agent.chat(query_text)
return {"agent": agent.name, "response": response}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.post("/agents/{name}")
async def query_agent(name: str, request: Request):
agent = agent_map.get(name.lower())
if not agent:
return JSONResponse({"error": f"Agent not found: {name}"}, status_code=404)
try:
body = await request.json()
response = agent.chat(body.get("query", ""))
return {"agent": agent.name, "response": response}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/agents/list")
async def list_agents():
return {"agents": [{"name": a.name, "role": a.role} for a in agents]}
@app.get("/health")
async def health():
return {"status": "healthy", "agents": len(agents)}
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-agents",
"providers": [{"type": "agents-api", "name": "Multi-Agent API"}],
"endpoints": [
{"name": "agents", "provider_type": "agents-api"},
*[{"name": f"agents/{a.name.lower()}", "provider_type": "agents-api"} for a in agents]
]
}
uvicorn.run(app, host="127.0.0.1", port=8000)
def main():
print("=" * 60)
print("Agent.launch() and Agents.launch() Example")
print("=" * 60)
mode = sys.argv[1] if len(sys.argv) > 1 else "single"
if mode == "multi":
demo_multi_agent_launch()
else:
demo_single_agent_launch()
if __name__ == "__main__":
main()
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""
Multi-Agent Router as HTTP API Example
Demonstrates launching multiple agents as an HTTP API with:
- Router endpoint for automatic agent selection
- Per-agent endpoints
- Streaming support (SSE)
- Discovery endpoint
Usage:
# Run this example
python agents_as_api_router.py
# Or use CLI:
praisonai serve agents --file agents.yaml --port 8000
# Test with curl:
curl -X POST http://localhost:8000/agents \
-H "Content-Type: application/json" \
-d '{"query": "Research AI trends"}'
"""
import os
import sys
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
sys.exit(1)
def main():
print("=" * 60)
print("Multi-Agent Router as HTTP API Example")
print("=" * 60)
try:
from praisonaiagents import Agent, PraisonAIAgents
except ImportError:
print("Error: praisonaiagents not installed")
print("Install with: pip install praisonaiagents")
sys.exit(1)
# Create multiple agents
researcher = Agent(
name="Researcher",
role="Research Specialist",
goal="Find accurate and relevant information",
backstory="Expert at finding and synthesizing information from various sources.",
llm="gpt-4o-mini"
)
writer = Agent(
name="Writer",
role="Content Writer",
goal="Create engaging content from research",
backstory="Skilled writer who transforms research into readable content.",
llm="gpt-4o-mini"
)
analyst = Agent(
name="Analyst",
role="Data Analyst",
goal="Analyze data and provide insights",
backstory="Expert at analyzing data and extracting meaningful insights.",
llm="gpt-4o-mini"
)
agents = [researcher, writer, analyst]
print(f"Agents: {[a.name for a in agents]}")
# Create multi-agent system
praison = PraisonAIAgents(agents=agents)
print("\nLaunching multi-agent router as HTTP API...")
print("Endpoints:")
print(" POST /agents - Route to best agent")
print(" POST /agents/researcher - Query researcher")
print(" POST /agents/writer - Query writer")
print(" POST /agents/analyst - Query analyst")
print(" GET /agents/list - List all agents")
print(" GET /health - Health check")
print(" GET /__praisonai__/discovery - Discovery document")
print("\nPress Ctrl+C to stop")
try:
# Use Agents.launch() to start HTTP server
praison.launch(
port=8000,
host="127.0.0.1"
)
except KeyboardInterrupt:
print("\nServer stopped")
except Exception as e:
print(f"Error launching server: {e}")
print("\nFallback: Using manual FastAPI setup...")
launch_manual(agents)
def launch_manual(agents):
"""Manual FastAPI server setup as fallback."""
try:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import uvicorn
except ImportError:
print("Error: FastAPI/uvicorn not installed")
print("Install with: pip install fastapi uvicorn")
return
app = FastAPI(title="PraisonAI Multi-Agent API")
# Create agent lookup
agent_map = {a.name.lower(): a for a in agents}
@app.post("/agents")
async def route_query(request: Request):
"""Route query to best agent."""
try:
body = await request.json()
query = body.get("query", "")
if not query:
return JSONResponse({"error": "query required"}, status_code=400)
# Simple routing based on keywords
query_lower = query.lower()
if any(w in query_lower for w in ["research", "find", "search"]):
agent = agent_map.get("researcher", agents[0])
elif any(w in query_lower for w in ["write", "create", "draft"]):
agent = agent_map.get("writer", agents[0])
elif any(w in query_lower for w in ["analyze", "data", "insight"]):
agent = agent_map.get("analyst", agents[0])
else:
agent = agents[0]
response = agent.chat(query)
return {"agent": agent.name, "response": response}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.post("/agents/{agent_name}")
async def query_agent(agent_name: str, request: Request):
"""Query specific agent."""
agent = agent_map.get(agent_name.lower())
if not agent:
return JSONResponse({"error": f"Agent not found: {agent_name}"}, status_code=404)
try:
body = await request.json()
query = body.get("query", "")
response = agent.chat(query)
return {"agent": agent.name, "response": response}
except Exception as e:
return JSONResponse({"error": str(e)}, status_code=500)
@app.get("/agents/list")
async def list_agents():
return {"agents": [{"name": a.name, "role": a.role} for a in agents]}
@app.get("/health")
async def health():
return {"status": "healthy", "agents": len(agents)}
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-agents-router",
"providers": [{"type": "agents-api", "name": "Multi-Agent Router"}],
"endpoints": [
{"name": "agents", "provider_type": "agents-api"},
*[{"name": f"agents/{a.name.lower()}", "provider_type": "agents-api"} for a in agents]
]
}
@app.get("/")
async def root():
return {
"message": "PraisonAI Multi-Agent Router",
"agents": [a.name for a in agents],
"endpoints": ["/agents", "/agents/list", "/health"]
}
uvicorn.run(app, host="127.0.0.1", port=8000)
if __name__ == "__main__":
main()
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/env python3
"""
Unified Endpoints Client Example
Demonstrates using the praisonai endpoints CLI to interact with any PraisonAI server.
Works with recipe, agents-api, mcp, a2a, a2u, and tools-mcp servers.
Usage:
# Start any server first (e.g., unified server)
praisonai serve unified --port 8765
# Then run this example
python endpoints_unified_client.py
# Or use CLI directly:
praisonai endpoints list
praisonai endpoints types
praisonai endpoints health
praisonai endpoints discovery
"""
import json
import os
import subprocess
import sys
def run_cli(args: list) -> tuple:
"""Run praisonai endpoints CLI command."""
cmd = ["python3", "-m", "praisonai.cli.main", "endpoints"] + args
result = subprocess.run(cmd, capture_output=True, text=True)
return result.returncode, result.stdout, result.stderr
def main():
print("=" * 60)
print("PraisonAI Unified Endpoints Client Example")
print("=" * 60)
server_url = os.environ.get("PRAISONAI_ENDPOINTS_URL", "http://localhost:8765")
print(f"Server URL: {server_url}")
# 1. List provider types
print("\n--- Provider Types ---")
code, out, err = run_cli(["types", "--format", "json"])
if code == 0:
types = json.loads(out)
print(f"Supported types: {[t['type'] for t in types]}")
else:
print(f"Error: {err}")
# 2. Health check
print("\n--- Health Check ---")
code, out, err = run_cli(["health", "--url", server_url])
if code == 0:
print("✓ Server is healthy")
print(out.strip())
elif code == 8:
print("✗ Connection error - server not running")
print("\nStart a server first:")
print(" praisonai serve unified --port 8765")
print(" praisonai serve agents --file agents.yaml --port 8765")
print(" praisonai serve a2a --port 8765")
return 1
else:
print(f"✗ Health check failed: {err}")
return 1
# 3. Discovery document
print("\n--- Discovery Document ---")
code, out, err = run_cli(["discovery", "--url", server_url])
if code == 0:
try:
discovery = json.loads(out)
print(f"Server: {discovery.get('server_name', 'unknown')}")
print(f"Schema version: {discovery.get('schema_version', 'unknown')}")
providers = discovery.get('providers', [])
print(f"Providers: {[p.get('type') for p in providers]}")
endpoints = discovery.get('endpoints', [])
print(f"Endpoints: {[e.get('name') for e in endpoints]}")
except json.JSONDecodeError:
print(out.strip())
else:
print(f"Discovery not available: {err}")
# 4. List endpoints
print("\n--- List Endpoints ---")
code, out, err = run_cli(["list", "--url", server_url, "--format", "json"])
if code == 0:
try:
endpoints = json.loads(out)
if isinstance(endpoints, list):
for ep in endpoints[:5]: # Show first 5
print(f" - {ep.get('name')}: {ep.get('description', '')[:50]}")
else:
print(out.strip()[:200])
except json.JSONDecodeError:
print(out.strip()[:200])
else:
print(f"List failed: {err}")
# 5. Filter by type
print("\n--- Filter by Provider Type ---")
for ptype in ["agents-api", "a2a", "recipe"]:
code, out, err = run_cli(["list", "--url", server_url, "--type", ptype])
if code == 0 and out.strip():
print(f" {ptype}: {len(out.strip().split(chr(10)))} endpoints")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
return 0
if __name__ == "__main__":
sys.exit(main())
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env python3
"""
MCP HTTP Server Example
Demonstrates launching an MCP server with HTTP transport:
- HTTP-based MCP protocol
- Tool registration
- Discovery endpoint
Usage:
# Run this example
python mcp_http_server.py
# Or use CLI:
praisonai serve mcp --transport http --port 8080
# Test with curl:
curl http://localhost:8080/mcp/tools
curl -X POST http://localhost:8080/mcp/tools/call \
-H "Content-Type: application/json" \
-d '{"tool": "search", "arguments": {"query": "AI news"}}'
"""
import sys
def main():
print("=" * 60)
print("MCP HTTP Server Example")
print("=" * 60)
try:
from fastapi import FastAPI
import uvicorn
except ImportError:
print("Error: FastAPI/uvicorn not installed")
print("Install with: pip install fastapi uvicorn")
sys.exit(1)
# Define tools
def search(query: str) -> str:
"""Search the web for information."""
return f"Search results for: {query}"
def calculate(expression: str) -> str:
"""Calculate a math expression safely."""
try:
# Safe eval for basic math
allowed = set("0123456789+-*/.() ")
if all(c in allowed for c in expression):
return str(eval(expression))
return "Error: Invalid expression"
except Exception as e:
return f"Error: {e}"
def get_weather(city: str) -> str:
"""Get weather for a city (mock)."""
return f"Weather in {city}: Sunny, 72°F"
tools = {
"search": {"func": search, "description": "Search the web for information"},
"calculate": {"func": calculate, "description": "Calculate a math expression"},
"get_weather": {"func": get_weather, "description": "Get weather for a city"},
}
app = FastAPI(title="PraisonAI MCP Server")
@app.get("/mcp/tools")
async def list_tools():
"""List available MCP tools."""
return {
"tools": [
{
"name": name,
"description": info["description"],
"inputSchema": {
"type": "object",
"properties": {
list(info["func"].__code__.co_varnames)[0]: {"type": "string"}
},
"required": [list(info["func"].__code__.co_varnames)[0]]
}
}
for name, info in tools.items()
]
}
@app.post("/mcp/tools/call")
async def call_tool(request: dict):
"""Call an MCP tool."""
tool_name = request.get("tool")
arguments = request.get("arguments", {})
if tool_name not in tools:
return {"error": f"Tool not found: {tool_name}"}
try:
func = tools[tool_name]["func"]
# Get first argument
arg_name = list(func.__code__.co_varnames)[0]
arg_value = arguments.get(arg_name, "")
result = func(arg_value)
return {"result": result, "tool": tool_name}
except Exception as e:
return {"error": str(e)}
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-mcp",
"providers": [{"type": "mcp", "name": "MCP Server", "capabilities": ["list-tools", "call-tool"]}],
"endpoints": [{"name": "mcp", "provider_type": "mcp"}]
}
@app.get("/health")
async def health():
return {"status": "healthy", "tools": len(tools)}
@app.get("/")
async def root():
return {
"message": "PraisonAI MCP Server (HTTP)",
"tools": list(tools.keys()),
"endpoints": ["/mcp/tools", "/mcp/tools/call", "/health"]
}
print(f"Tools: {list(tools.keys())}")
print("\nStarting MCP HTTP server on http://localhost:8080")
print("List tools: GET http://localhost:8080/mcp/tools")
print("Call tool: POST http://localhost:8080/mcp/tools/call")
print("\nPress Ctrl+C to stop")
uvicorn.run(app, host="127.0.0.1", port=8080)
if __name__ == "__main__":
main()
+350
View File
@@ -0,0 +1,350 @@
#!/usr/bin/env python3
"""
PraisonAI Recipe Server Advanced Features Example
Demonstrates:
1. Rate limiting
2. Request size limits
3. Metrics endpoint
4. Admin reload endpoint
5. OpenAPI specification
6. Workers configuration
7. OpenTelemetry tracing
Prerequisites:
- pip install praisonai[serve]
- Set OPENAI_API_KEY environment variable
Usage:
# Run this example
python recipe_serve_features.py
"""
import json
import os
import urllib.request
import urllib.error
# Configuration
SERVER_URL = os.environ.get("PRAISONAI_ENDPOINTS_URL", "http://localhost:8765")
API_KEY = os.environ.get("PRAISONAI_API_KEY", "test-api-key")
def make_request(method: str, path: str, data: dict = None, headers: dict = None) -> dict:
"""Make HTTP request to server."""
url = f"{SERVER_URL}{path}"
default_headers = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
}
if headers:
default_headers.update(headers)
body = json.dumps(data).encode() if data else None
try:
req = urllib.request.Request(url, data=body, headers=default_headers, method=method)
with urllib.request.urlopen(req, timeout=30) as response:
return {
"status": response.status,
"data": json.loads(response.read().decode()),
"headers": dict(response.headers)
}
except urllib.error.HTTPError as e:
body = e.read().decode() if e.fp else ""
try:
error_data = json.loads(body)
except json.JSONDecodeError:
error_data = {"raw": body}
return {
"status": e.code,
"error": error_data,
"headers": dict(e.headers) if hasattr(e, 'headers') else {}
}
except urllib.error.URLError as e:
return {"status": 0, "error": str(e.reason)}
def test_health():
"""Test health endpoint."""
print("\n" + "=" * 60)
print("TEST: Health Check")
print("=" * 60)
result = make_request("GET", "/health")
if result.get("status") == 200:
data = result["data"]
print("✓ Server healthy")
print(f" Service: {data.get('service')}")
print(f" Version: {data.get('version')}")
return True
else:
print(f"✗ Server unhealthy: {result.get('error')}")
return False
def test_openapi():
"""Test OpenAPI specification endpoint."""
print("\n" + "=" * 60)
print("TEST: OpenAPI Specification")
print("=" * 60)
result = make_request("GET", "/openapi.json")
if result.get("status") == 200:
spec = result["data"]
print("✓ OpenAPI spec available")
print(f" Version: {spec.get('openapi')}")
print(f" Title: {spec.get('info', {}).get('title')}")
print(f" Paths: {list(spec.get('paths', {}).keys())[:5]}...")
return True
else:
print(f"✗ OpenAPI not available: {result.get('error')}")
return False
def test_metrics():
"""Test metrics endpoint."""
print("\n" + "=" * 60)
print("TEST: Metrics Endpoint")
print("=" * 60)
result = make_request("GET", "/metrics")
if result.get("status") == 200:
# Metrics returns plain text, not JSON
print("✓ Metrics endpoint available")
print(" (Prometheus format)")
return True
elif result.get("status") == 404:
print("⚠ Metrics endpoint not enabled")
print(" Enable with: --enable_metrics")
return True # Not a failure, just not enabled
else:
print(f"✗ Metrics error: {result.get('error')}")
return False
def test_admin_reload():
"""Test admin reload endpoint."""
print("\n" + "=" * 60)
print("TEST: Admin Reload Endpoint")
print("=" * 60)
result = make_request("POST", "/admin/reload")
if result.get("status") == 200:
data = result["data"]
print("✓ Admin reload successful")
print(f" Status: {data.get('status')}")
print(f" Timestamp: {data.get('timestamp')}")
return True
elif result.get("status") == 404:
print("⚠ Admin endpoint not enabled")
print(" Enable with: --enable_admin")
return True # Not a failure, just not enabled
elif result.get("status") == 401:
print("⚠ Admin endpoint requires authentication")
return True # Expected behavior
else:
print(f"✗ Admin reload error: {result.get('error')}")
return False
def test_rate_limiting():
"""Test rate limiting."""
print("\n" + "=" * 60)
print("TEST: Rate Limiting")
print("=" * 60)
# Make rapid requests
rate_limited = False
retry_after = None
for i in range(20):
result = make_request("GET", "/v1/recipes")
if result.get("status") == 429:
rate_limited = True
retry_after = result.get("headers", {}).get("Retry-After")
error = result.get("error", {})
print(f"✓ Rate limited after {i} requests")
print(f" Error code: {error.get('error', {}).get('code')}")
print(f" Retry-After: {retry_after}")
break
if not rate_limited:
print("⚠ Rate limiting not triggered (may not be enabled)")
print(" Enable with: --rate_limit 10")
return True
def test_request_size_limit():
"""Test request size limit."""
print("\n" + "=" * 60)
print("TEST: Request Size Limit")
print("=" * 60)
# Create a large payload
large_data = {
"recipe": "test",
"input": {"data": "x" * 100000} # ~100KB
}
result = make_request("POST", "/v1/recipes/run", large_data)
if result.get("status") == 413:
error = result.get("error", {})
print("✓ Request size limit enforced")
print(f" Error code: {error.get('error', {}).get('code')}")
return True
elif result.get("status") in [200, 400, 404]:
print("⚠ Request size limit not triggered (limit may be higher)")
print(" Set with: --max_request_size 1000")
return True
else:
print(f" Response: {result.get('status')} - {result.get('error')}")
return True
def test_list_recipes():
"""Test listing recipes."""
print("\n" + "=" * 60)
print("TEST: List Recipes")
print("=" * 60)
result = make_request("GET", "/v1/recipes")
if result.get("status") == 200:
recipes = result["data"].get("recipes", [])
print(f"✓ Found {len(recipes)} recipes")
for r in recipes[:3]:
print(f" - {r.get('name')} ({r.get('version', 'unknown')})")
if len(recipes) > 3:
print(f" ... and {len(recipes) - 3} more")
return True
elif result.get("status") == 401:
print("⚠ Authentication required")
return True
else:
print(f"✗ Error: {result.get('error')}")
return False
def demonstrate_programmatic_usage():
"""Demonstrate programmatic server configuration."""
print("\n" + "=" * 60)
print("DEMO: Programmatic Configuration")
print("=" * 60)
print("""
# Rate Limiter
from praisonai.recipe.serve import create_rate_limiter
limiter = create_rate_limiter(requests_per_minute=100)
allowed, retry_after = limiter.check("client-id")
# Metrics Collector
from praisonai.recipe.serve import MetricsCollector
metrics = MetricsCollector()
metrics.record_request("/health", "GET", 200, 0.01)
print(metrics.get_prometheus_metrics())
# OpenAPI Spec
from praisonai.recipe.serve import get_openapi_spec
spec = get_openapi_spec({"enable_metrics": True, "enable_admin": True})
print(spec["paths"].keys())
# Template Search Paths
from praisonai.recipe.core import get_template_search_paths
paths = get_template_search_paths()
print(f"Searching {len(paths)} paths for recipes")
# Reload Registry
from praisonai.recipe.core import reload_registry
reload_registry()
print("Registry reloaded")
""")
# Actually run the demos
try:
from praisonai.recipe.serve import create_rate_limiter, MetricsCollector, get_openapi_spec
from praisonai.recipe.core import get_template_search_paths, reload_registry
# Rate limiter
limiter = create_rate_limiter(requests_per_minute=100)
allowed, _ = limiter.check("demo-client")
print(f"✓ Rate limiter: allowed={allowed}")
# Metrics
metrics = MetricsCollector()
metrics.record_request("/demo", "GET", 200, 0.01)
prom = metrics.get_prometheus_metrics()
print(f"✓ Metrics: {len(prom)} chars of Prometheus format")
# OpenAPI
spec = get_openapi_spec({"enable_metrics": True})
print(f"✓ OpenAPI: {len(spec['paths'])} paths defined")
# Search paths
paths = get_template_search_paths()
print(f"✓ Template paths: {len(paths)} directories")
# Reload
reload_registry()
print("✓ Registry reloaded")
except ImportError as e:
print(f"⚠ Import error: {e}")
print(" Install with: pip install praisonai[serve]")
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Recipe Server Advanced Features")
print("=" * 60)
print(f"Server URL: {SERVER_URL}")
print(f"API Key: {'*' * 8}..." if API_KEY else "API Key: Not set")
# Check if server is running
if not test_health():
print("\n" + "=" * 60)
print("Server not running. Start it with:")
print("=" * 60)
print(f"""
# Basic start
praisonai recipe serve
# With all features enabled
export PRAISONAI_API_KEY={API_KEY}
praisonai recipe serve \\
--auth api-key \\
--rate_limit 100 \\
--enable_metrics \\
--enable_admin \\
--workers 2
""")
# Still demonstrate programmatic usage
demonstrate_programmatic_usage()
return
# Run all tests
test_openapi()
test_metrics()
test_admin_reload()
test_rate_limiting()
test_request_size_limit()
test_list_recipes()
# Demonstrate programmatic usage
demonstrate_programmatic_usage()
print("\n" + "=" * 60)
print("All tests completed!")
print("=" * 60)
if __name__ == "__main__":
main()
+29
View File
@@ -0,0 +1,29 @@
# PraisonAI Recipe Server Configuration
# This file configures the recipe HTTP server
# Server binding
host: 127.0.0.1
port: 8765
# Authentication
# Options: none, api-key, jwt
auth: api-key
# API key for authentication (or use PRAISONAI_API_KEY env var)
# api_key: your-secret-key-here
# Recipe filtering (optional)
# Only serve these specific recipes
# recipes:
# - my-recipe
# - another-recipe
# Performance
# Preload recipes on startup for faster first request
preload: true
# CORS configuration (for web clients)
# cors_origins: "https://app.example.com,https://admin.example.com"
# Logging level
# log_level: info
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env python3
"""
PraisonAI Recipe Server Example
This example demonstrates how to:
1. Start the recipe server with configuration
2. Use API key authentication
3. Make authenticated requests
Prerequisites:
- pip install praisonai[serve]
- Set OPENAI_API_KEY environment variable
- Set PRAISONAI_API_KEY for authentication
Usage:
# Terminal 1: Start server with config
praisonai recipe serve --config serve.yaml
# Terminal 2: Run this example
python serve_example.py
"""
import json
import os
import sys
import urllib.request
import urllib.error
# Configuration
SERVER_URL = os.environ.get("PRAISONAI_ENDPOINTS_URL", "http://localhost:8765")
API_KEY = os.environ.get("PRAISONAI_API_KEY", "test-api-key")
def make_request(method: str, path: str, data: dict = None) -> dict:
"""Make authenticated HTTP request to server."""
url = f"{SERVER_URL}{path}"
headers = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
}
body = json.dumps(data).encode() if data else None
try:
req = urllib.request.Request(url, data=body, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=30) as response:
return {"status": response.status, "data": json.loads(response.read().decode())}
except urllib.error.HTTPError as e:
body = e.read().decode() if e.fp else ""
return {"status": e.code, "error": body}
except urllib.error.URLError as e:
return {"status": 0, "error": str(e.reason)}
def check_health():
"""Check server health."""
print("\n=== Health Check ===")
result = make_request("GET", "/health")
if result.get("status") == 200:
data = result["data"]
print("✓ Server healthy")
print(f" Service: {data.get('service')}")
print(f" Version: {data.get('version')}")
return True
else:
print(f"✗ Server unhealthy: {result.get('error')}")
return False
def list_recipes():
"""List available recipes."""
print("\n=== List Recipes ===")
result = make_request("GET", "/v1/recipes")
if result.get("status") == 200:
recipes = result["data"].get("recipes", [])
print(f"Found {len(recipes)} recipes:")
for r in recipes:
print(f" - {r['name']} ({r['version']})")
return recipes
elif result.get("status") == 401:
print("✗ Authentication failed - check API key")
return []
else:
print(f"✗ Error: {result.get('error')}")
return []
def describe_recipe(name: str):
"""Get recipe details."""
print(f"\n=== Describe Recipe: {name} ===")
result = make_request("GET", f"/v1/recipes/{name}")
if result.get("status") == 200:
info = result["data"]
print(f"Name: {info.get('name')}")
print(f"Version: {info.get('version')}")
print(f"Description: {info.get('description')}")
return info
else:
print(f"✗ Error: {result.get('error')}")
return None
def invoke_recipe(name: str, input_data: dict, dry_run: bool = True):
"""Invoke a recipe."""
print(f"\n=== Invoke Recipe: {name} (dry_run={dry_run}) ===")
result = make_request("POST", "/v1/recipes/run", {
"recipe": name,
"input": input_data,
"options": {"dry_run": dry_run}
})
if result.get("status") == 200:
data = result["data"]
print("✓ Success")
print(f" Run ID: {data.get('run_id')}")
print(f" Status: {data.get('status')}")
if data.get("output"):
print(f" Output: {json.dumps(data.get('output'), indent=2)[:200]}...")
return data
elif result.get("status") == 401:
print("✗ Authentication failed - check API key")
return None
else:
print(f"✗ Error: {result.get('error')}")
return None
def main():
"""Main example function."""
print("=" * 60)
print("PraisonAI Recipe Server Example")
print("=" * 60)
print(f"Server URL: {SERVER_URL}")
print(f"API Key: {API_KEY[:8]}..." if API_KEY else "API Key: Not set")
# Check health
if not check_health():
print("\nServer not running. Start it with:")
print(f" export PRAISONAI_API_KEY={API_KEY}")
print(" praisonai recipe serve --config serve.yaml")
sys.exit(1)
# List recipes
recipes = list_recipes()
if not recipes:
print("\nNo recipes available or auth failed")
sys.exit(1)
# Use first recipe
recipe_name = recipes[0]["name"]
# Describe recipe
describe_recipe(recipe_name)
# Invoke recipe (dry run)
invoke_recipe(recipe_name, {"query": "Hello from serve example"}, dry_run=True)
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+222
View File
@@ -0,0 +1,222 @@
#!/usr/bin/env python3
"""
Tools as MCP Server Example
Demonstrates exposing Python tools as an MCP server:
- Register custom functions as MCP tools
- SSE transport for Claude Desktop/Cursor
- Stdio transport for local integration
Usage:
# Run this example (SSE mode)
python tools_as_mcp_server.py
# Or use CLI:
praisonai serve tools --port 8081
# Test with curl:
curl http://localhost:8081/sse
"""
import sys
def main():
print("=" * 60)
print("Tools as MCP Server Example")
print("=" * 60)
try:
from praisonaiagents.mcp import ToolsMCPServer
except ImportError:
print("Error: praisonaiagents[mcp] not installed")
print("Install with: pip install 'praisonaiagents[mcp]'")
print("\nFallback: Using manual implementation...")
run_manual_server()
return
# Define custom tools
def search_web(query: str) -> str:
"""Search the web for information."""
return f"Search results for: {query}"
def analyze_text(text: str) -> str:
"""Analyze text for sentiment and key points."""
word_count = len(text.split())
return f"Analysis: {word_count} words, sentiment: neutral"
def translate(text: str, target_language: str = "Spanish") -> str:
"""Translate text to target language (mock)."""
return f"[Translated to {target_language}]: {text}"
def summarize(text: str) -> str:
"""Summarize long text."""
words = text.split()
if len(words) > 20:
return " ".join(words[:20]) + "..."
return text
# Create MCP server
server = ToolsMCPServer(name="praisonai-tools")
# Register tools
server.register_tool(search_web)
server.register_tool(analyze_text)
server.register_tool(translate)
server.register_tool(summarize)
print(f"Registered tools: {[search_web.__name__, analyze_text.__name__, translate.__name__, summarize.__name__]}")
print("\nStarting MCP server with SSE transport...")
print("SSE endpoint: http://localhost:8081/sse")
print("\nClaude Desktop config (claude_desktop_config.json):")
print(''' {
"mcpServers": {
"praisonai-tools": {
"url": "http://localhost:8081/sse"
}
}
}''')
print("\nPress Ctrl+C to stop")
server.run(transport="sse", host="0.0.0.0", port=8081)
def run_manual_server():
"""Manual MCP server implementation as fallback."""
try:
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import uvicorn
import json
import asyncio
except ImportError:
print("Error: FastAPI/uvicorn not installed")
print("Install with: pip install fastapi uvicorn")
sys.exit(1)
# Define tools
tools = {
"search_web": {
"func": lambda query: f"Search results for: {query}",
"description": "Search the web for information",
"params": {"query": "string"}
},
"analyze_text": {
"func": lambda text: f"Analysis: {len(text.split())} words",
"description": "Analyze text for sentiment and key points",
"params": {"text": "string"}
},
}
app = FastAPI(title="PraisonAI Tools MCP Server")
@app.get("/sse")
async def sse_endpoint():
"""SSE endpoint for MCP."""
async def event_stream():
# Send initial tools list
tools_list = {
"jsonrpc": "2.0",
"method": "tools/list",
"result": {
"tools": [
{
"name": name,
"description": info["description"],
"inputSchema": {
"type": "object",
"properties": {k: {"type": v} for k, v in info["params"].items()},
"required": list(info["params"].keys())
}
}
for name, info in tools.items()
]
}
}
yield f"data: {json.dumps(tools_list)}\n\n"
# Keep connection alive
while True:
await asyncio.sleep(30)
yield f"data: {json.dumps({'type': 'ping'})}\n\n"
return StreamingResponse(
event_stream(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"}
)
@app.post("/messages/")
async def handle_message(request: dict):
"""Handle MCP messages."""
method = request.get("method")
params = request.get("params", {})
req_id = request.get("id")
if method == "tools/list":
return {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"tools": [
{
"name": name,
"description": info["description"],
"inputSchema": {
"type": "object",
"properties": {k: {"type": v} for k, v in info["params"].items()}
}
}
for name, info in tools.items()
]
}
}
elif method == "tools/call":
tool_name = params.get("name")
arguments = params.get("arguments", {})
if tool_name not in tools:
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Tool not found: {tool_name}"}}
try:
func = tools[tool_name]["func"]
arg = list(arguments.values())[0] if arguments else ""
result = func(arg)
return {
"jsonrpc": "2.0",
"id": req_id,
"result": {"content": [{"type": "text", "text": result}]}
}
except Exception as e:
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32000, "message": str(e)}}
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Unknown method: {method}"}}
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-tools-mcp",
"providers": [{"type": "tools-mcp", "name": "Tools MCP Server", "capabilities": ["list-tools", "call-tool"]}],
"endpoints": [{"name": "tools", "provider_type": "tools-mcp"}]
}
@app.get("/")
async def root():
return {
"message": "PraisonAI Tools MCP Server",
"tools": list(tools.keys()),
"sse": "/sse",
"messages": "/messages/"
}
print(f"Tools: {list(tools.keys())}")
print("\nStarting Tools MCP server on http://localhost:8081")
print("SSE endpoint: http://localhost:8081/sse")
print("\nPress Ctrl+C to stop")
uvicorn.run(app, host="127.0.0.1", port=8081)
if __name__ == "__main__":
main()
+241
View File
@@ -0,0 +1,241 @@
#!/usr/bin/env python3
"""
Unified Server Example
Demonstrates launching a unified server with all provider types:
- agents-api: Single/multi-agent HTTP API
- recipe: Recipe runner endpoints
- mcp: MCP server
- a2a: Agent-to-agent protocol
- a2u: Agent-to-user event stream
Usage:
# Run this example
python unified_server.py
# Or use CLI:
praisonai serve unified --port 8765
# Test with curl:
curl http://localhost:8765/__praisonai__/discovery
curl http://localhost:8765/health
"""
import os
import sys
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable not set")
sys.exit(1)
def main():
print("=" * 60)
print("Unified Server Example")
print("=" * 60)
try:
from fastapi import FastAPI
import uvicorn
from praisonaiagents import Agent
except ImportError as e:
print(f"Error: Missing dependency - {e}")
print("Install with: pip install praisonaiagents fastapi uvicorn")
sys.exit(1)
# Create agents
assistant = Agent(
name="Assistant",
role="Helpful AI Assistant",
goal="Help users with their questions",
llm="gpt-4o-mini"
)
researcher = Agent(
name="Researcher",
role="Research Specialist",
goal="Find accurate information",
llm="gpt-4o-mini"
)
agents = [assistant, researcher]
agent_map = {a.name.lower(): a for a in agents}
# Create unified app
app = FastAPI(
title="PraisonAI Unified Server",
description="Unified server with all PraisonAI providers"
)
# Discovery endpoint
@app.get("/__praisonai__/discovery")
async def discovery():
return {
"schema_version": "1.0.0",
"server_name": "praisonai-unified",
"providers": [
{"type": "agents-api", "name": "Agents API", "capabilities": ["invoke", "health"]},
{"type": "recipe", "name": "Recipe Runner", "capabilities": ["list", "describe", "invoke"]},
{"type": "mcp", "name": "MCP Server", "capabilities": ["list-tools", "call-tool"]},
{"type": "a2a", "name": "A2A Protocol", "capabilities": ["agent-card", "message-send"]},
{"type": "a2u", "name": "A2U Event Stream", "capabilities": ["subscribe", "stream"]},
],
"endpoints": [
{"name": "agents", "provider_type": "agents-api", "description": "Multi-agent router"},
{"name": "agent", "provider_type": "agents-api", "description": "Single agent endpoint"},
{"name": "mcp/tools", "provider_type": "mcp", "description": "MCP tools"},
{"name": "a2a", "provider_type": "a2a", "description": "A2A protocol"},
{"name": "a2u/events", "provider_type": "a2u", "description": "Event stream"},
]
}
# Health endpoint
@app.get("/health")
async def health():
return {
"status": "healthy",
"providers": ["agents-api", "recipe", "mcp", "a2a", "a2u"],
"agents": len(agents)
}
# Agents API endpoints
@app.post("/agents")
async def route_agents(request: dict):
query = request.get("query", "")
agent = agents[0] # Simple routing
try:
response = agent.chat(query)
return {"agent": agent.name, "response": response}
except Exception as e:
return {"error": str(e)}
@app.post("/agents/{name}")
async def query_agent(name: str, request: dict):
agent = agent_map.get(name.lower())
if not agent:
return {"error": f"Agent not found: {name}"}
try:
response = agent.chat(request.get("query", ""))
return {"agent": agent.name, "response": response}
except Exception as e:
return {"error": str(e)}
@app.get("/agents/list")
async def list_agents():
return {"agents": [{"name": a.name, "role": a.role} for a in agents]}
# Single agent endpoint
@app.post("/agent")
async def single_agent(request: dict):
query = request.get("query", "")
try:
response = assistant.chat(query)
return {"response": response}
except Exception as e:
return {"error": str(e)}
# MCP endpoints
mcp_tools = {
"search": {"description": "Search the web", "func": lambda q: f"Results for: {q}"},
"calculate": {"description": "Calculate expression", "func": lambda e: str(eval(e)) if e.replace(" ", "").replace("+", "").replace("-", "").replace("*", "").replace("/", "").replace(".", "").isdigit() or True else "Error"},
}
@app.get("/mcp/tools")
async def list_mcp_tools():
return {
"tools": [
{"name": name, "description": info["description"]}
for name, info in mcp_tools.items()
]
}
@app.post("/mcp/tools/call")
async def call_mcp_tool(request: dict):
tool_name = request.get("tool")
args = request.get("arguments", {})
if tool_name not in mcp_tools:
return {"error": f"Tool not found: {tool_name}"}
try:
result = mcp_tools[tool_name]["func"](list(args.values())[0] if args else "")
return {"result": result}
except Exception as e:
return {"error": str(e)}
# A2A endpoints
@app.get("/.well-known/agent.json")
async def agent_card():
return {
"name": "PraisonAI Unified",
"description": "Unified PraisonAI server with multiple agents",
"url": "http://localhost:8765/a2a",
"version": "1.0.0",
"capabilities": {"streaming": True}
}
@app.post("/a2a")
async def a2a_endpoint(request: dict):
method = request.get("method")
params = request.get("params", {})
req_id = request.get("id")
if method == "message/send":
message = params.get("message", {})
parts = message.get("parts", [])
text = "".join(p.get("text", "") for p in parts if p.get("type") == "text")
try:
response = assistant.chat(text)
return {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"message": {
"role": "agent",
"parts": [{"type": "text", "text": response}]
}
}
}
except Exception as e:
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32000, "message": str(e)}}
return {"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Unknown method: {method}"}}
# A2U endpoints
@app.get("/a2u/info")
async def a2u_info():
return {
"name": "A2U Event Stream",
"version": "1.0.0",
"streams": ["events"],
"event_types": ["agent.started", "agent.response", "agent.completed"]
}
# Root endpoint
@app.get("/")
async def root():
return {
"message": "PraisonAI Unified Server",
"providers": ["agents-api", "recipe", "mcp", "a2a", "a2u"],
"discovery": "/__praisonai__/discovery",
"health": "/health",
"docs": "/docs"
}
print(f"Agents: {[a.name for a in agents]}")
print("\nStarting unified server on http://localhost:8765")
print("\nEndpoints:")
print(" GET /__praisonai__/discovery - Discovery document")
print(" GET /health - Health check")
print(" POST /agents - Multi-agent router")
print(" POST /agent - Single agent")
print(" GET /mcp/tools - List MCP tools")
print(" GET /.well-known/agent.json - A2A agent card")
print(" POST /a2a - A2A messages")
print(" GET /a2u/info - A2U info")
print("\nPress Ctrl+C to stop")
uvicorn.run(app, host="127.0.0.1", port=8765)
if __name__ == "__main__":
main()
+128
View File
@@ -0,0 +1,128 @@
"""
Example: Using pandas as a custom tool with PraisonAI Agent
This example shows how to wrap pandas functions as tools
that can be used with Agent().
"""
import pandas as pd
from io import StringIO
# Define pandas wrapper tools
def analyze_csv_data(csv_data: str) -> str:
"""Analyze CSV data using pandas DataFrame.
Args:
csv_data: CSV-formatted string data
Returns:
Analysis summary including shape, columns, and statistics
"""
df = pd.read_csv(StringIO(csv_data))
summary = f"""DataFrame Analysis:
- Shape: {df.shape[0]} rows, {df.shape[1]} columns
- Columns: {list(df.columns)}
- Data Types: {dict(df.dtypes)}
- Summary Statistics:
{df.describe().to_string()}"""
return summary
def filter_dataframe(csv_data: str, column: str, condition: str, value: str) -> str:
"""Filter a DataFrame based on a condition.
Args:
csv_data: CSV-formatted string data
column: Column name to filter on
condition: Condition type ('equals', 'greater', 'less', 'contains')
value: Value to compare against
Returns:
Filtered data as CSV string
"""
df = pd.read_csv(StringIO(csv_data))
if condition == 'equals':
filtered = df[df[column] == value]
elif condition == 'greater':
filtered = df[df[column] > float(value)]
elif condition == 'less':
filtered = df[df[column] < float(value)]
elif condition == 'contains':
filtered = df[df[column].str.contains(value, na=False)]
else:
return f"Unknown condition: {condition}"
return filtered.to_csv(index=False)
def calculate_statistics(csv_data: str, column: str) -> str:
"""Calculate statistics for a specific column.
Args:
csv_data: CSV-formatted string data
column: Column name to analyze
Returns:
Statistics summary for the column
"""
df = pd.read_csv(StringIO(csv_data))
if column not in df.columns:
return f"Column '{column}' not found. Available: {list(df.columns)}"
col = df[column]
if pd.api.types.is_numeric_dtype(col):
stats = f"""Statistics for '{column}':
- Count: {col.count()}
- Mean: {col.mean():.2f}
- Std: {col.std():.2f}
- Min: {col.min()}
- Max: {col.max()}
- Median: {col.median()}"""
else:
stats = f"""Statistics for '{column}':
- Count: {col.count()}
- Unique: {col.nunique()}
- Top: {col.mode().iloc[0] if len(col.mode()) > 0 else 'N/A'}
- Sample values: {list(col.head(3))}"""
return stats
if __name__ == "__main__":
# Test data
test_csv = """name,age,salary,department
Alice,30,50000,Engineering
Bob,25,45000,Marketing
Charlie,35,60000,Engineering
Diana,28,52000,Sales
Eve,32,55000,Marketing"""
print("=== Test: analyze_csv_data ===")
print(analyze_csv_data(test_csv))
print()
print("=== Test: filter_dataframe ===")
print(filter_dataframe(test_csv, "age", "greater", "28"))
print()
print("=== Test: calculate_statistics ===")
print(calculate_statistics(test_csv, "salary"))
print()
# Example with Agent (requires praisonaiagents)
print("=== Agent Usage Example ===")
print("""
from praisonaiagents import Agent
agent = Agent(
name="data_analyst",
role="Data Analyst",
goal="Analyze data using pandas tools",
tools=[analyze_csv_data, filter_dataframe, calculate_statistics]
)
result = agent.start("Analyze this data and find the average salary")
""")
+25
View File
@@ -0,0 +1,25 @@
"""Example: Discover tools from installed packages."""
# Discover from praisonaiagents built-in tools
try:
from praisonaiagents.tools import TOOL_MAPPINGS
print("Built-in tools from praisonaiagents:")
for name in list(TOOL_MAPPINGS.keys())[:10]:
print(f" - {name}")
print(f" ... and {len(TOOL_MAPPINGS) - 10} more")
except ImportError:
print("praisonaiagents not installed")
# Discover from praisonai_tools
try:
import praisonai_tools
print("\nTools from praisonai_tools:")
# Check for video module
try:
from praisonai_tools import video
print(" - praisonai_tools.video (video editing)")
except ImportError:
pass
except ImportError:
print("praisonai_tools not installed")
+18
View File
@@ -0,0 +1,18 @@
"""Example: Resolve tool names to callable tools."""
from praisonai.templates.tool_override import (
create_tool_registry_with_overrides,
resolve_tools,
)
# Create registry with defaults
registry = create_tool_registry_with_overrides(include_defaults=True)
print(f"Registry contains {len(registry)} tools")
# Resolve tool names
tool_names = ["shell_tool", "internet_search"]
resolved = resolve_tools(tool_names, registry=registry)
print(f"\nResolved {len(resolved)} tools:")
for tool in resolved:
print(f" - {getattr(tool, '__name__', type(tool).__name__)}")
+14
View File
@@ -0,0 +1,14 @@
"""Example: Configure tool sources for templates."""
from praisonai.templates.tool_override import create_tool_registry_with_overrides
# Create registry with tools_sources
registry = create_tool_registry_with_overrides(
tools_sources=["praisonai_tools.video"],
include_defaults=True,
)
print(f"Registry with tools_sources: {len(registry)} tools")
# List some tools
for name in list(registry.keys())[:10]:
print(f" - {name}")
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
"""
Import time benchmark for praisonaiagents.
This benchmark measures the import time of the praisonaiagents package
and verifies that heavy dependencies are not loaded at import time.
Usage:
python benchmarks/import_time.py
CI Gate:
- PASS: import time < 200ms
- WARN: import time 200-300ms
- FAIL: import time > 300ms
"""
import sys
import time
import statistics
def clear_modules():
"""Clear all praisonai and litellm related modules from cache."""
to_remove = [m for m in sys.modules.keys()
if 'praison' in m or 'litellm' in m]
for mod in to_remove:
del sys.modules[mod]
def measure_import_time(runs: int = 5) -> dict:
"""
Measure import time over multiple runs.
Returns:
dict with min, max, median, mean times in milliseconds
"""
times = []
for _ in range(runs):
clear_modules()
start = time.perf_counter()
import praisonaiagents # noqa: F401
end = time.perf_counter()
times.append((end - start) * 1000)
# Clean up for next run
if 'praisonaiagents' in sys.modules:
del sys.modules['praisonaiagents']
times.sort()
return {
'times': times,
'min': min(times),
'max': max(times),
'median': statistics.median(times),
'mean': statistics.mean(times),
'stdev': statistics.stdev(times) if len(times) > 1 else 0,
}
def check_lazy_imports() -> dict:
"""
Check that heavy dependencies are NOT loaded after importing praisonaiagents.
Returns:
dict with module names and whether they are loaded
"""
clear_modules()
import praisonaiagents # noqa: F401
heavy_modules = [
'litellm',
'chromadb',
'mem0',
'requests',
]
results = {}
for mod in heavy_modules:
results[mod] = mod in sys.modules
return results
def main():
"""Run the benchmark and print results."""
print("=" * 60)
print("PraisonAI Agents Import Time Benchmark")
print("=" * 60)
# Measure import time
print("\n[1/2] Measuring import time (5 runs)...")
results = measure_import_time(runs=5)
print(f"\nImport times (ms): {[round(t, 1) for t in results['times']]}")
print(f" Min: {results['min']:.1f} ms")
print(f" Max: {results['max']:.1f} ms")
print(f" Median: {results['median']:.1f} ms")
print(f" Mean: {results['mean']:.1f} ms")
print(f" StdDev: {results['stdev']:.1f} ms")
# Check lazy imports
print("\n[2/2] Checking lazy imports...")
lazy_results = check_lazy_imports()
print("\nHeavy modules loaded at import time:")
all_lazy = True
for mod, loaded in lazy_results.items():
status = "LOADED (BAD)" if loaded else "NOT LOADED (GOOD)"
print(f" {mod}: {status}")
if loaded:
all_lazy = False
# Determine pass/fail
print("\n" + "=" * 60)
print("RESULTS")
print("=" * 60)
median_time = results['median']
if median_time < 200:
time_status = "PASS"
time_msg = f"Import time {median_time:.0f}ms < 200ms target"
elif median_time < 300:
time_status = "WARN"
time_msg = f"Import time {median_time:.0f}ms between 200-300ms"
else:
time_status = "FAIL"
time_msg = f"Import time {median_time:.0f}ms > 300ms limit"
lazy_status = "PASS" if all_lazy else "FAIL"
lazy_msg = "All heavy deps lazy loaded" if all_lazy else "Some heavy deps loaded eagerly"
print(f"\nImport Time: [{time_status}] {time_msg}")
print(f"Lazy Imports: [{lazy_status}] {lazy_msg}")
overall = "PASS" if time_status != "FAIL" and lazy_status == "PASS" else "FAIL"
print(f"\nOverall: [{overall}]")
# Exit code for CI
return 0 if overall == "PASS" else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Memory usage benchmark for praisonaiagents.
This benchmark measures the memory footprint of importing praisonaiagents
and verifies it stays within acceptable limits.
Usage:
python benchmarks/memory_usage.py
CI Gate:
- PASS: memory < 30MB
- WARN: memory 30-45MB
- FAIL: memory > 45MB
"""
import sys
import tracemalloc
def clear_modules():
"""Clear all praisonai and litellm related modules from cache."""
to_remove = [m for m in sys.modules.keys()
if 'praison' in m or 'litellm' in m]
for mod in to_remove:
del sys.modules[mod]
def measure_memory() -> dict:
"""
Measure memory usage after importing praisonaiagents.
Returns:
dict with current and peak memory in MB
"""
clear_modules()
tracemalloc.start()
import praisonaiagents # noqa: F401
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
return {
'current_bytes': current,
'peak_bytes': peak,
'current_mb': current / 1024 / 1024,
'peak_mb': peak / 1024 / 1024,
}
def main():
"""Run the benchmark and print results."""
print("=" * 60)
print("PraisonAI Agents Memory Usage Benchmark")
print("=" * 60)
print("\nMeasuring memory usage...")
results = measure_memory()
print(f"\nMemory Usage:")
print(f" Current: {results['current_mb']:.1f} MB")
print(f" Peak: {results['peak_mb']:.1f} MB")
# Determine pass/fail based on peak memory
peak_mb = results['peak_mb']
print("\n" + "=" * 60)
print("RESULTS")
print("=" * 60)
if peak_mb < 30:
status = "PASS"
msg = f"Memory {peak_mb:.1f}MB < 30MB target"
elif peak_mb < 45:
status = "WARN"
msg = f"Memory {peak_mb:.1f}MB between 30-45MB"
else:
status = "FAIL"
msg = f"Memory {peak_mb:.1f}MB > 45MB limit"
print(f"\nMemory: [{status}] {msg}")
# Exit code for CI
return 0 if status != "FAIL" else 1
if __name__ == "__main__":
sys.exit(main())
Loaded 100 of 510 files, more files were not shown because too many files have changed in this diff. Show more