Compare commits

...
108 Commits
Author SHA1 Message Date
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
Mervin Praison d8e944c1d3 Release v2.5.4 2025-12-26 06:49:33 +00:00
Mervin Praison 79b2b88f72 Release v2.5.3 2025-12-26 05:54:09 +00:00
Mervin Praison f5dfbd5670 fix: resolve Core Tests failures in knowledge/reranker integration
- Fix #1: MemoryConfig Pydantic validation - add _prepare_mem0_config() to strip
  PraisonAI-specific reranker fields (enabled, default_rerank) before passing to
  mem0, which only accepts provider and config fields

- Fix #2: LLM Reranker 'Chat' object not callable - check if client.chat is
  callable, not just if it exists. OpenAI client has chat as namespace object.
  Also handle max_completion_tokens vs max_tokens for different model versions.

- Fix #3: Chroma vector store metadata validation - ensure non-empty metadata
  dicts by adding placeholder key when metadata is empty or None

- Fix test file issues: add user_id parameter (required by mem0 API), handle
  dict return type from knowledge.search, use gpt-4o-mini for reranker test
  (gpt-5-nano returns empty responses with max_completion_tokens=10)
2025-12-26 05:52:46 +00:00
Mervin Praison aa6aa5933d fix: update test files to use gpt-5-nano for cheaper CI runs
- Update test_workflow_patterns.py to use gpt-5-nano instead of gpt-4o/gpt-4o-mini
- Also set OPENAI_MODEL_NAME=gpt-5-nano as CI secret
2025-12-26 05:26:40 +00:00
Mervin Praison ff3a4f2016 Release v2.5.2 2025-12-26 05:25:08 +00:00
Mervin Praison 0d5444fc23 fix: add missing praisonai.db module to git
- Add praisonai/db/ module that was being ignored by *.db pattern
- This fixes ModuleNotFoundError: No module named 'praisonai.db' in CI tests
2025-12-26 04:54:05 +00:00
Mervin Praison d7d5dab17b fix: add missing db module to git and update .gitignore
- Add praisonaiagents/db/ module that was being ignored by *.db pattern
- Add exception in .gitignore for the db module directory
- This fixes ModuleNotFoundError: No module named 'praisonaiagents.db' in CI
2025-12-26 04:49:31 +00:00
Mervin Praison 05678394e6 fix: remove sys.exit() at module level in test files causing pytest INTERNALERROR
- test_mini_agents_fix.py: Convert module-level sys.exit(1) to pytest.mark.skipif pattern
- test_xai_fix.py: Convert to proper pytest test function with cleanup

These sys.exit() calls at module level caused pytest to crash during test collection
with INTERNALERROR, breaking all CI pipelines.
2025-12-26 04:46:58 +00:00
Mervin Praison 54cddc09b4 Release v2.5.1 2025-12-26 04:23:51 +00:00
Mervin Praison 9cbab01785 Release v2.5.0 2025-12-26 02:20:59 +00:00
Mervin Praison de9d4bd3c6 Release v2.4.4 2025-12-26 01:21:26 +00:00
Mervin Praison aba2265e5e Release v2.4.3 2025-12-26 01:01:30 +00:00
Mervin Praison ebb9b24bff Release v2.4.2 2025-12-25 00:29:49 +00:00
Mervin Praison 759ef2c655 Update database initialization to use db() shortcut and expand tools table with 100+ tools 2025-12-25 00:24:48 +00:00
Mervin Praison cb4318f6e8 Release v2.4.1 2025-12-24 15:00:45 +00:00
Mervin Praison d9bb869d5e Add documentation for 6 new features: Shadow Git Checkpoints, Background Tasks, Policy Engine, Thinking Budgets, Output Styles, and Context Compaction 2025-12-24 08:02:48 +00:00
Mervin Praison 34b6aeb76b Release v2.4.0 2025-12-24 07:47:53 +00:00
Mervin Praison 078b7801e1 Add 'response' field to workflow API for consistency with single-agent endpoint 2025-12-23 17:50:07 +00:00
Mervin Praison a970e849b4 Release v2.3.87 2025-12-23 16:08:35 +00:00
Mervin Praison 8e68f4e71c Release v2.3.86 2025-12-23 15:23:31 +00:00
Mervin Praison 308758cdc2 Release v2.3.85 2025-12-23 15:07:46 +00:00
Mervin Praison f8fa61b082 Release v2.3.84 2025-12-23 14:57:15 +00:00
Mervin Praison 955d236924 Release v2.3.84 2025-12-23 13:20:08 +00:00
Mervin Praison d9d63c3a13 Release v2.3.83 2025-12-23 13:06:42 +00:00
Mervin Praison 5bee6eb470 Release v2.3.83 2025-12-23 11:42:47 +00:00
Mervin Praison 7cb1676b7c Release v2.3.82 2025-12-23 09:41:09 +00:00
Mervin Praison e2e9c3f9ee Release v2.3.81 2025-12-23 08:11:31 +00:00
Mervin Praison cbe8beeca6 Release v2.3.80 2025-12-23 07:54:07 +00:00
Mervin Praison f7b66a52b7 Release v2.3.79 2025-12-23 07:27:35 +00:00
Mervin Praison 6dbf194312 Release v2.3.78 2025-12-23 06:46:15 +00:00
Mervin Praison 335e8d7e47 Release v2.3.77 2025-12-23 06:28:26 +00:00
Mervin Praison d65840e092 Release v2.3.76 2025-12-23 05:40:52 +00:00
Mervin Praison 5a13571fdd Release v2.3.75 2025-12-22 19:11:32 +00:00
Mervin Praison e3b48c2526 Release v2.3.74 2025-12-22 17:01:50 +00:00
Mervin Praison 8d32238b4c Release v2.3.73 2025-12-22 15:47:51 +00:00
Mervin Praison c17b1298bb Reorganize README feature table with improved categorization and hierarchy 2025-12-22 14:50:37 +00:00
Mervin Praison ec6c150315 Release v2.3.72 2025-12-22 13:44:48 +00:00
Mervin Praison 3d26cedd5d Release v2.3.71 2025-12-22 11:59:12 +00:00
Mervin Praison 8c735a60b2 Release v2.3.70 2025-12-22 10:43:48 +00:00
Mervin Praison 2f5f2f1c13 Release v2.3.69 2025-12-22 10:40:53 +00:00
Mervin Praison 0253073c68 Release v2.3.68 2025-12-22 10:35:45 +00:00
Mervin Praison 7f0e334e8c Release v2.3.67 2025-12-22 09:14:33 +00:00
Mervin Praison cacf1097ef Release v2.3.66 2025-12-22 08:50:02 +00:00
Mervin Praison 09f01919d2 Fix duplicate --max-retries argument conflict in CLI parser 2025-12-21 05:19:08 +00:00
Mervin Praison 92397615f8 Release v2.3.65 2025-12-20 21:49:04 +00:00
Mervin Praison 4b21943a53 Release v2.3.64 2025-12-20 19:57:39 +00:00
Mervin Praison af56a753bd Release v2.3.63 2025-12-20 12:02:44 +00:00
Mervin Praison 15c2559a3c Release v2.3.62 2025-12-20 11:59:46 +00:00
Mervin Praison 3215bdc0a6 Release v2.3.61 2025-12-20 11:15:22 +00:00
Mervin Praison 0ff0d83744 fix: Preserve real API keys for integration tests in conftest.py
- Check for @pytest.mark.integration marker
- Check if test file is in integration/ directory
- This prevents conftest from overriding real API keys with 'test-key'
2025-12-20 03:58:13 +00:00
Mervin Praison 8f956f91dd fix: Improve API key validation in integration test skip conditions
- Check for 'sk-' prefix and minimum length (40 chars) to detect invalid keys
- This ensures tests are skipped when using placeholder/test API keys in CI
2025-12-20 03:54:58 +00:00
Mervin Praison 954f6ac33d fix: Skip integration tests when using test API key
- test_auto_generator_integration.py: Skip when OPENAI_API_KEY contains 'test'
- test_model_routing_real.py: Skip test_real_openai_call when using test key
- test_cli_integrations.py: Skip all tests when using test key

These tests require real API credentials and should not run in CI
when only a placeholder test key is available.
2025-12-20 03:51:22 +00:00
Mervin Praison 264d11d8d9 fix: Fix failing unit tests for ClaudeCodeSDK and QueryRewriter CLI
- test_use_sdk_option: Updated test to match actual behavior where use_sdk
  is only True when SDK is available (use_sdk and CLAUDE_SDK_AVAILABLE)
- test_applies_rewrite_before_agent: Fixed mocking to properly mock
  _run_with_status_display and praisonaiagents submodules
2025-12-20 03:47:28 +00:00
Mervin Praison 88da2bdd7b Release v2.3.60 2025-12-20 03:35:28 +00:00
Mervin Praison b84e6c2460 Release v2.3.59 2025-12-20 03:28:48 +00:00
Mervin Praison 0434b23ada Release v2.3.58 2025-12-20 03:08:31 +00:00
Mervin Praison a9951e0694 Release v2.3.57 2025-12-19 16:47:09 +00:00
Mervin Praison 073062cd96 Release v2.3.56 2025-12-19 16:14:58 +00:00
Mervin Praison 936b422876 Release v2.3.55 2025-12-19 16:05:38 +00:00
Mervin Praison 99ab421ce2 Release v2.3.54 2025-12-19 16:04:43 +00:00
Mervin Praison c1f334905e Release v2.3.53 2025-12-19 15:38:30 +00:00
Mervin Praison 6d3ba7cdf8 Release v2.3.52 2025-12-19 15:34:19 +00:00
Mervin Praison 96616498d2 Release v2.3.51 2025-12-19 15:25:30 +00:00
Mervin Praison 1cad345415 Release v2.3.50 2025-12-19 15:19:29 +00:00
Mervin Praison 802e7e52f9 fix(readme): correct CLI docs URLs to include /docs/ prefix
Changed all https://docs.praison.ai/cli/* URLs to https://docs.praison.ai/docs/cli/*
Fixed 39 URLs total
2025-12-19 13:01:53 +00:00
Mervin Praison 53704f234c Release v2.3.49 2025-12-19 12:49:12 +00:00
Mervin Praison b575994d91 docs(readme): update AI commit CLI with security scanning and auto mode
- Add full auto mode (-a) with stage, security check, commit, push
- Document security scanning features
- Add --no-verify flag documentation
- List detected sensitive patterns
2025-12-19 12:35:49 +00:00
Mervin Praison 7ed8596261 Release v2.3.48 2025-12-19 12:35:02 +00:00
Mervin Praison deef65c4bb Release v2.3.47 2025-12-19 12:23:05 +00:00
Mervin Praison d51327effd Release v2.3.46 2025-12-19 12:22:29 +00:00
Mervin Praison 30ce8857e8 fix: suppress crewai.cli.config INFO log at startup 2025-12-19 12:18:23 +00:00
Mervin Praison 397874ccfc Release v2.3.45 2025-12-19 12:16:12 +00:00
Mervin Praison 2016902e9a docs: Add examples README with quick links to docs 2025-12-19 11:14:24 +00:00
Mervin Praison d2d19511da docs: Update README with Model Router info and fix links
- Rename 'Router Agent' to 'Model Router' for consistency
- Fix docs link to point to /features/model-router
- Add model-routing template CLI command
- Add link to Model Router documentation
2025-12-19 11:13:48 +00:00
Mervin Praison bc9579b497 Add Code category with individual examples for external CLI integrations
- Add Code category in Key Features table (like Workflows)
- Add individual examples for each external agent:
  - claude_code_example.py
  - gemini_cli_example.py
  - codex_cli_example.py
  - cursor_cli_example.py
  - external_agents_example.py (all integrations)
  - code_editing_example.py
- Link to individual docs pages for each integration
- Organize code-related features under Code category
2025-12-19 11:07:25 +00:00
Mervin Praison 3161389341 Add External Agents CLI documentation to README
- Add External Agents feature to Key Features table
- Update Code Editing docs link to /code/editing
- Add External Agents CLI section with examples
- Include Python API usage examples
- Add environment variables documentation
- Link to detailed docs at docs.praison.ai/code/external-agents
2025-12-19 11:01:24 +00:00
Mervin Praison b01eb2b8fa Release v2.3.44 2025-12-19 10:50:33 +00:00
Mervin Praison e609fb7425 Release v2.3.43 2025-12-19 10:32:33 +00:00
Mervin Praison 168ef98473 feat: Implement all remaining AutoAgents improvements (TDD)
TODO 2: Single-Agent Option
- Add SingleAgentStructure Pydantic model
- Add single_agent parameter to AutoGenerator and WorkflowAutoGenerator

TODO 3: LLM-Based Pattern Recommendation
- Add PatternRecommendation Pydantic model (pattern, reasoning, confidence)
- Add recommend_pattern_llm() method to WorkflowAutoGenerator

TODO 4: Validation Gates
- Add ValidationGate Pydantic model (criteria, pass_action, fail_action)
- Add optional gates field to WorkflowStructure

TODO 6: Pattern Support for AutoGenerator
- Add pattern parameter to AutoGenerator
- Add recommend_pattern() method to AutoGenerator
- Add pattern-specific guidance in get_user_content()

TODO 7: Merge Support for WorkflowAutoGenerator
- Add merge parameter to generate() method
- Add merge_with_existing_workflow() method

TODO 10: Framework Support for WorkflowAutoGenerator
- Add framework parameter to WorkflowAutoGenerator
- Default framework is 'praisonai'

Test Coverage:
- 51 tests pass (up from 34)
- 17 new tests added using TDD approach
- All tests verify new functionality
2025-12-19 10:29:40 +00:00
Mervin Praison ce2c2926f9 refactor: Add BaseAutoGenerator class and improve WorkflowAutoGenerator
- Create BaseAutoGenerator with shared functionality (DRY principle)
  - Lazy-loaded instructor client (LiteLLM or OpenAI fallback)
  - Environment variable handling for model/API configuration
  - analyze_complexity() static method for task complexity detection
  - get_available_tools() static method for tool list
  - AVAILABLE_TOOLS constant shared between generators

- Update AutoGenerator to inherit from BaseAutoGenerator
  - Removes ~40 lines of duplicate code
  - Maintains all existing functionality

- Update WorkflowAutoGenerator to inherit from BaseAutoGenerator
  - Removes ~40 lines of duplicate code
  - Add dynamic agent count based on task complexity
  - Add tools list to workflow prompts
  - Improved prompt with 3-step analysis

- Add 8 new unit tests for new functionality
  - TestBaseAutoGenerator: complexity analysis, tools list
  - TestWorkflowDynamicAgentCount: prompt improvements

All 34 tests pass with no performance impact.
2025-12-19 10:23:29 +00:00
Mervin Praison 0a569e2b46 docs: Add AutoAgents workflow patterns examples and update README
- Add autoagents_workflow_patterns.py with all 6 workflow patterns
- Update auto_agents_example.py with new features and CLI examples
- Add orchestrator-workers and evaluator-optimizer patterns to README CLI section
- Update pattern options table with all 6 patterns
- Add documentation links to examples
2025-12-19 09:54:05 +00:00
Mervin Praison 054aea8f66 Add MCP Registry badge and ignore MCP tokens 2025-12-18 22:18:33 +00:00
Mervin Praison 34f1293cfc Release v2.3.42 2025-12-18 22:13:08 +00:00
Mervin Praison 7c1e32afc0 upate 2025-12-18 22:11:02 +00:00
830 changed files with 165501 additions and 2021 deletions

No files matched your search

+6 -1
View File
@@ -77,4 +77,9 @@ agents/praisonaiagents/praisonaiagents.egg-info
.qodo
CopilotKit*
.gemini
issue_details.json
issue_details.json
# MCP Registry tokens
.mcpregistry_*
*.log
+1259 -257
View File
File diff suppressed because it is too large. Load diff
+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.3.41" \
"praisonai>=2.7.4" \
"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.3.41" \
"praisonai>=2.7.4" \
"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.3.41" \
"praisonai>=2.7.4" \
"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/
```
+67
View File
@@ -0,0 +1,67 @@
# PraisonAI Examples
This folder contains examples for PraisonAI. For detailed documentation, visit [docs.praison.ai](https://docs.praison.ai).
## Structure
```
examples/
├── python/ # Python examples
│ ├── agents/ # Agent examples (single, multi, router, etc.)
│ ├── workflows/ # Workflow patterns (routing, parallel, loop)
│ ├── tools/ # Custom tools examples
│ ├── mcp/ # MCP protocol 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
```
## Quick Links
| Category | Examples | Docs |
|----------|----------|------|
| **Agents** | [python/agents/](python/agents/) | [📖](https://docs.praison.ai/concepts/agents) |
| **Workflows** | [python/workflows/](python/workflows/) | [📖](https://docs.praison.ai/features/workflows) |
| **Model Router** | [python/agents/router-agent-cost-optimization.py](python/agents/router-agent-cost-optimization.py) | [📖](https://docs.praison.ai/features/model-router) |
| **MCP** | [python/mcp/](python/mcp/) | [📖](https://docs.praison.ai/mcp) |
| **Memory** | [python/memory/](python/memory/) | [📖](https://docs.praison.ai/concepts/memory) |
| **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
```bash
# Install PraisonAI
pip install praisonai
# Set API key
export OPENAI_API_KEY=your_key_here
# Run an example
python examples/python/agents/single-agent.py
```
## CLI Commands
See the main [README.md](../README.md#-cli--no-code-interface) for all CLI commands.
+35
View File
@@ -0,0 +1,35 @@
"""
Async Runs Examples
===================
This directory contains examples for the PraisonAI Async Jobs API.
Examples:
---------
1. sdk_submit_poll_result.py - Python SDK example for submit/poll/result
2. cli_submit_poll_result.sh - Bash/curl example for submit/poll/result
3. idempotency.sh - Demonstrates idempotency key usage
4. cancel.sh - Demonstrates job cancellation
5. sse_stream.sh - Demonstrates SSE streaming
Prerequisites:
--------------
1. Set OPENAI_API_KEY environment variable
2. Start the jobs server:
cd /path/to/praisonai-package/src/praisonai
python -m uvicorn praisonai.jobs.server:create_app --port 8005 --factory
3. Run examples:
python sdk_submit_poll_result.py
bash cli_submit_poll_result.sh
bash idempotency.sh
bash cancel.sh
bash sse_stream.sh
Environment Variables:
----------------------
- OPENAI_API_KEY: Required for agent execution
- PRAISONAI_BASE_URL: API server URL (default: http://127.0.0.1:8005)
"""
+54
View File
@@ -0,0 +1,54 @@
#!/bin/bash
# CLI Example: Cancel a Running Job
#
# This example demonstrates how to cancel a running job.
#
# Requirements:
# - Jobs server running on http://127.0.0.1:8005
#
# Usage:
# bash cancel.sh
set -e
API_URL="${PRAISONAI_BASE_URL:-http://127.0.0.1:8005}"
echo "============================================================"
echo "PraisonAI Job Cancellation Example"
echo "============================================================"
# Submit a long-running job
echo ""
echo "1. Submitting a job..."
RESPONSE=$(curl -s -X POST "$API_URL/api/v1/runs" \
-H "Content-Type: application/json" \
-d '{"prompt": "Write a detailed essay about the history of computing."}')
JOB_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo " Job ID: $JOB_ID"
# Wait briefly
echo ""
echo "2. Waiting 1 second..."
sleep 1
# Cancel the job
echo ""
echo "3. Cancelling job..."
CANCEL_RESPONSE=$(curl -s -X POST "$API_URL/api/v1/runs/$JOB_ID/cancel")
STATUS=$(echo "$CANCEL_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
echo " Status after cancel: $STATUS"
# Verify cancellation
echo ""
echo "4. Verification:"
if [ "$STATUS" = "cancelled" ]; then
echo " ✓ SUCCESS: Job was cancelled"
else
echo " ℹ Job status: $STATUS (may have completed before cancel)"
fi
echo ""
echo "============================================================"
echo "Cancellation example completed!"
echo "============================================================"
@@ -0,0 +1,75 @@
#!/bin/bash
# CLI Example: Submit, Poll, and Get Result for Async Jobs
#
# This example demonstrates how to use the PraisonAI CLI to:
# 1. Submit an async job
# 2. Check job status
# 3. Get the result
#
# Requirements:
# - OPENAI_API_KEY environment variable set
# - Jobs server running on http://127.0.0.1:8005
#
# Usage:
# bash cli_submit_poll_result.sh
set -e
API_URL="${PRAISONAI_BASE_URL:-http://127.0.0.1:8005}"
echo "============================================================"
echo "PraisonAI Async Jobs CLI Example"
echo "============================================================"
# Check if server is running
echo ""
echo "Checking server health..."
if ! curl -s "$API_URL/health" > /dev/null 2>&1; then
echo "✗ Server not available at $API_URL"
echo " Start the server with: python -m uvicorn praisonai.jobs.server:create_app --port 8005 --factory"
exit 1
fi
echo "✓ Server is healthy"
# 1. Submit a job
echo ""
echo "1. Submitting job..."
RESPONSE=$(curl -s -X POST "$API_URL/api/v1/runs" \
-H "Content-Type: application/json" \
-d '{"prompt": "What is 2+2? Answer with just the number."}')
JOB_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo " Job ID: $JOB_ID"
# 2. Poll for status
echo ""
echo "2. Polling for status..."
while true; do
STATUS_RESPONSE=$(curl -s "$API_URL/api/v1/runs/$JOB_ID")
STATUS=$(echo "$STATUS_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
PROGRESS=$(echo "$STATUS_RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['progress']['percentage'])")
echo " Status: $STATUS | Progress: ${PROGRESS}%"
if [ "$STATUS" = "succeeded" ] || [ "$STATUS" = "failed" ] || [ "$STATUS" = "cancelled" ]; then
break
fi
sleep 2
done
# 3. Get result
echo ""
echo "3. Getting result..."
if [ "$STATUS" = "succeeded" ]; then
RESULT=$(curl -s "$API_URL/api/v1/runs/$JOB_ID/result")
echo " Result: $(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['result'])")"
echo " Duration: $(echo "$RESULT" | python3 -c "import sys,json; print(f\"{json.load(sys.stdin)['duration_seconds']:.2f}s\")")"
else
echo " Job did not succeed: $STATUS"
fi
echo ""
echo "============================================================"
echo "Example completed!"
echo "============================================================"
+57
View File
@@ -0,0 +1,57 @@
#!/bin/bash
# CLI Example: Idempotency Key Usage
#
# This example demonstrates how idempotency keys prevent duplicate job submissions.
# Submitting the same request with the same idempotency key returns the existing job.
#
# Requirements:
# - Jobs server running on http://127.0.0.1:8005
#
# Usage:
# bash idempotency.sh
set -e
API_URL="${PRAISONAI_BASE_URL:-http://127.0.0.1:8005}"
IDEM_KEY="example-idem-key-$(date +%s)"
echo "============================================================"
echo "PraisonAI Idempotency Key Example"
echo "============================================================"
# First submission
echo ""
echo "1. First submission with Idempotency-Key: $IDEM_KEY"
RESPONSE1=$(curl -s -X POST "$API_URL/api/v1/runs" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEM_KEY" \
-d '{"prompt": "What is 1+1?"}')
JOB_ID1=$(echo "$RESPONSE1" | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo " Job ID: $JOB_ID1"
# Second submission with same key
echo ""
echo "2. Second submission with SAME Idempotency-Key: $IDEM_KEY"
RESPONSE2=$(curl -s -X POST "$API_URL/api/v1/runs" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEM_KEY" \
-d '{"prompt": "Different prompt but same key"}')
JOB_ID2=$(echo "$RESPONSE2" | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo " Job ID: $JOB_ID2"
# Verify same job ID
echo ""
echo "3. Verification:"
if [ "$JOB_ID1" = "$JOB_ID2" ]; then
echo " ✓ SUCCESS: Same job ID returned (no duplicate created)"
else
echo " ✗ FAILURE: Different job IDs returned"
exit 1
fi
echo ""
echo "============================================================"
echo "Idempotency example completed!"
echo "============================================================"
@@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""
SDK Example: Submit, Poll, and Get Result for Async Jobs
This example demonstrates how to use the PraisonAI Jobs SDK to:
1. Submit an async job
2. Poll for status
3. Get the result
Requirements:
- OPENAI_API_KEY environment variable set
- Jobs server running on http://127.0.0.1:8005
Usage:
python sdk_submit_poll_result.py
"""
import os
import time
import httpx
# Configuration
API_URL = os.getenv("PRAISONAI_BASE_URL", "http://127.0.0.1:8005")
POLL_INTERVAL = 2 # seconds
def submit_job(prompt: str, idempotency_key: str = None) -> dict:
"""Submit a job and return the response."""
headers = {}
if idempotency_key:
headers["Idempotency-Key"] = idempotency_key
with httpx.Client(timeout=30.0) as client:
response = client.post(
f"{API_URL}/api/v1/runs",
json={"prompt": prompt},
headers=headers if headers else None
)
response.raise_for_status()
return response.json()
def get_status(job_id: str) -> dict:
"""Get job status."""
with httpx.Client(timeout=30.0) as client:
response = client.get(f"{API_URL}/api/v1/runs/{job_id}")
response.raise_for_status()
return response.json()
def get_result(job_id: str) -> dict:
"""Get job result."""
with httpx.Client(timeout=30.0) as client:
response = client.get(f"{API_URL}/api/v1/runs/{job_id}/result")
response.raise_for_status()
return response.json()
def wait_for_completion(job_id: str, max_wait: int = 120) -> dict:
"""Poll until job completes."""
start = time.time()
while time.time() - start < max_wait:
status = get_status(job_id)
print(f" Status: {status['status']} | Progress: {status['progress']['percentage']:.0f}%")
if status["status"] in ("succeeded", "failed", "cancelled"):
return status
# Honor retry_after if present
wait_time = status.get("retry_after") or POLL_INTERVAL
time.sleep(wait_time)
raise TimeoutError(f"Job {job_id} did not complete within {max_wait}s")
def main():
print("=" * 60)
print("PraisonAI Async Jobs SDK Example")
print("=" * 60)
# Check if server is running
try:
with httpx.Client(timeout=5.0) as client:
health = client.get(f"{API_URL}/health")
health.raise_for_status()
print(f"✓ Server healthy: {health.json()['status']}")
except Exception as e:
print(f"✗ Server not available at {API_URL}: {e}")
print(" Start the server with: python -m uvicorn praisonai.jobs.server:create_app --port 8005 --factory")
return
# 1. Submit a job
print("\n1. Submitting job...")
prompt = "What is the capital of France? Answer in one word."
result = submit_job(prompt)
job_id = result["job_id"]
print(f" Job ID: {job_id}")
print(f" Status: {result['status']}")
print(f" Poll URL: {result['poll_url']}")
# 2. Wait for completion
print("\n2. Waiting for completion...")
final_status = wait_for_completion(job_id)
print(f" Final status: {final_status['status']}")
# 3. Get result
if final_status["status"] == "succeeded":
print("\n3. Getting result...")
result = get_result(job_id)
print(f" Result: {result['result']}")
print(f" Duration: {result['duration_seconds']:.2f}s")
else:
print(f"\n3. Job did not succeed: {final_status.get('error', 'Unknown error')}")
print("\n" + "=" * 60)
print("Example completed successfully!")
print("=" * 60)
if __name__ == "__main__":
main()
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
# CLI Example: SSE Streaming
#
# This example demonstrates how to stream job progress via Server-Sent Events.
#
# Requirements:
# - Jobs server running on http://127.0.0.1:8005
#
# Usage:
# bash sse_stream.sh
set -e
API_URL="${PRAISONAI_BASE_URL:-http://127.0.0.1:8005}"
echo "============================================================"
echo "PraisonAI SSE Streaming Example"
echo "============================================================"
# Submit a job
echo ""
echo "1. Submitting job..."
RESPONSE=$(curl -s -X POST "$API_URL/api/v1/runs" \
-H "Content-Type: application/json" \
-d '{"prompt": "Count from 1 to 5."}')
JOB_ID=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['job_id'])")
echo " Job ID: $JOB_ID"
# Stream progress
echo ""
echo "2. Streaming progress (Ctrl+C to stop)..."
echo " Connecting to: $API_URL/api/v1/runs/$JOB_ID/stream"
echo ""
# Use curl to stream SSE events (timeout after 60s)
curl -s -N --max-time 60 "$API_URL/api/v1/runs/$JOB_ID/stream" | while read -r line; do
if [[ "$line" == data:* ]]; then
data="${line#data: }"
if [ "$data" = "[DONE]" ]; then
echo " Stream completed"
break
fi
echo " Event: $data"
fi
done
echo ""
echo "============================================================"
echo "Streaming example completed!"
echo "============================================================"
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env python3
"""
Basic Background Tasks Example for PraisonAI Agents.
This example demonstrates how to use the background task system to:
1. Run tasks asynchronously
2. Track task progress
3. Cancel running tasks
4. Handle task completion
Usage:
python basic_background.py
"""
import asyncio
import time
from praisonaiagents.background import BackgroundRunner, BackgroundConfig, TaskStatus
async def main():
print("=" * 60)
print("Background Tasks Demo")
print("=" * 60)
# Create a background runner with config
config = BackgroundConfig(max_concurrent_tasks=3)
runner = BackgroundRunner(config=config)
# Define some example tasks
def slow_task(duration: float, name: str) -> str:
"""A slow task that simulates work."""
print(f" 🔄 Task '{name}' starting (will take {duration}s)")
time.sleep(duration)
return f"Task '{name}' completed after {duration}s"
async def async_task(duration: float, name: str) -> str:
"""An async task that simulates work."""
print(f" 🔄 Async task '{name}' starting (will take {duration}s)")
await asyncio.sleep(duration)
return f"Async task '{name}' completed after {duration}s"
# Submit tasks
print("\n--- Submitting Tasks ---")
task1 = await runner.submit(slow_task, args=(1.0, "quick-job"), name="task1")
print(f"✅ Submitted task 1: {task1.id[:8]}")
task2 = await runner.submit(slow_task, args=(2.0, "medium-job"), name="task2")
print(f"✅ Submitted task 2: {task2.id[:8]}")
task3 = await runner.submit(async_task, args=(1.5, "async-job"), name="task3")
print(f"✅ Submitted async task 3: {task3.id[:8]}")
# List all tasks
print("\n--- Task Status ---")
for task in runner.tasks:
print(f" [{task.id[:8]}] {task.status.value}")
# Wait for task 1 to complete
print("\n--- Waiting for Task 1 ---")
await task1.wait(timeout=5.0)
print(f"✅ Task 1 result: {task1.result}")
# Check status of all tasks
print("\n--- Updated Task Status ---")
for task in [task1, task2, task3]:
status = "✅" if task.status == TaskStatus.COMPLETED else "🔄"
print(f" {status} [{task.id[:8]}] {task.status.value}")
# Wait for all remaining tasks
print("\n--- Waiting for All Tasks ---")
await task2.wait(timeout=10.0)
await task3.wait(timeout=10.0)
# Final status
print("\n--- Final Results ---")
for task in [task1, task2, task3]:
if task.result:
print(f" ✅ {task.result}")
# Cleanup
runner.clear_completed()
print("\n✅ Cleared completed tasks")
print("\n" + "=" * 60)
print("Demo Complete!")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())
@@ -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()
+110
View File
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
"""
Basic Checkpoints Example for PraisonAI Agents.
This example demonstrates how to use the shadow git checkpointing system to:
1. Save checkpoints before making changes
2. List available checkpoints
3. View diffs between checkpoints
4. Restore to a previous checkpoint
Usage:
python basic_checkpoints.py
"""
import asyncio
import tempfile
from pathlib import Path
from praisonaiagents.checkpoints import CheckpointService
async def main():
# Create a temporary workspace for demonstration
with tempfile.TemporaryDirectory() as workspace:
print("=" * 60)
print("Shadow Git Checkpointing Demo")
print("=" * 60)
print(f"\nWorkspace: {workspace}")
# Create some initial files
test_file = Path(workspace) / "example.py"
test_file.write_text("# Initial content\nprint('Hello, World!')\n")
print(f"\n✅ Created initial file: {test_file.name}")
# Initialize the checkpoint service
service = CheckpointService(workspace_dir=workspace)
try:
# Initialize the shadow git repository
print("\n--- Initializing Checkpoint Service ---")
await service.initialize()
print("✅ Shadow git repository initialized")
# Save first checkpoint
print("\n--- Saving Checkpoint 1: Initial State ---")
result1 = await service.save("Initial state")
print(f"✅ Checkpoint saved: {result1.checkpoint.id[:8]}")
print(f" Message: {result1.checkpoint.message}")
# Make some changes
print("\n--- Making Changes ---")
test_file.write_text("# Modified content\nprint('Hello, PraisonAI!')\nprint('Checkpoints are awesome!')\n")
print("✅ Modified example.py")
# Create a new file
new_file = Path(workspace) / "utils.py"
new_file.write_text("def helper():\n return 'I help!'\n")
print("✅ Created utils.py")
# Save second checkpoint
print("\n--- Saving Checkpoint 2: After Changes ---")
result2 = await service.save("Added features")
print(f"✅ Checkpoint saved: {result2.checkpoint.id[:8]}")
# List all checkpoints
print("\n--- Listing All Checkpoints ---")
checkpoints = await service.list_checkpoints()
for i, cp in enumerate(checkpoints, 1):
print(f" {i}. [{cp.id[:8]}] {cp.message} ({cp.timestamp})")
# Show diff
print("\n--- Current Diff (uncommitted changes) ---")
diff = await service.diff()
if diff.files:
for f in diff.files:
print(f" {f.status}: {f.path}")
else:
print(" No uncommitted changes")
# Make more changes to show diff
test_file.write_text("# Even more changes\nprint('This will be reverted')\n")
print("\n✅ Made more changes to example.py")
diff = await service.diff()
print("\n--- New Diff ---")
if diff.files:
for f in diff.files:
print(f" {f.status}: {f.path}")
# Restore to checkpoint 2
print(f"\n--- Restoring to Checkpoint: {result2.checkpoint.id[:8]} ---")
await service.restore(result2.checkpoint.id)
print("✅ Restored successfully!")
# Verify restoration
content = test_file.read_text()
print(f"\n--- Verified Content After Restore ---")
print(content)
except Exception as e:
print(f"\n❌ Error: {e}")
raise
print("\n" + "=" * 60)
print("Demo Complete!")
print("=" * 60)
if __name__ == "__main__":
asyncio.run(main())
+93
View File
@@ -0,0 +1,93 @@
# Persistence CLI Commands
## Quick Reference
```bash
# Check database connectivity
praisonai persistence doctor \
--conversation-url postgresql://localhost:5432/praisonai \
--state-url redis://localhost:6379
# Run agent with persistence
praisonai persistence run \
--conversation-url postgresql://localhost:5432/praisonai \
--session-id my-session
# Resume a session
praisonai persistence resume \
--conversation-url postgresql://localhost:5432/praisonai \
--session-id my-session
# Export session to file
praisonai persistence export \
--conversation-url postgresql://localhost:5432/praisonai \
--session-id my-session \
--output session_backup.jsonl
# Import session from file
praisonai persistence import \
--conversation-url postgresql://localhost:5432/praisonai \
--file session_backup.jsonl
# Check schema status
praisonai persistence status \
--conversation-url postgresql://localhost:5432/praisonai \
--state-url redis://localhost:6379
# Apply migrations
praisonai persistence migrate \
--conversation-url postgresql://localhost:5432/praisonai \
--state-url redis://localhost:6379
```
## Environment Variables
Instead of CLI flags, you can use environment variables:
```bash
export PRAISON_CONVERSATION_URL=postgresql://localhost:5432/praisonai
export PRAISON_STATE_URL=redis://localhost:6379
export PRAISON_KNOWLEDGE_URL=http://localhost:6333
# Then run without URL flags
praisonai persistence doctor
praisonai persistence status
```
## Docker Setup
```bash
# Start all services
docker run -d --name praison-postgres \
-e POSTGRES_PASSWORD=praison123 \
-e POSTGRES_DB=praisonai \
-p 5432:5432 postgres:16
docker run -d --name praison-redis \
-p 6379:6379 redis:7
docker run -d --name praison-qdrant \
-p 6333:6333 -p 6334:6334 qdrant/qdrant
# Verify
docker ps
```
## Example Workflow
```bash
# 1. Start services
docker-compose up -d
# 2. Check connectivity
praisonai persistence doctor
# 3. Run agent
praisonai persistence run --session-id demo-session
# 4. Export for backup
praisonai persistence export --session-id demo-session --output backup.jsonl
# 5. Import to another environment
praisonai persistence import --file backup.jsonl
```
+124
View File
@@ -0,0 +1,124 @@
# PraisonAI Persistence CLI - End-to-End Guide
This guide demonstrates the CLI commands for database persistence.
## Prerequisites
```bash
pip install "praisonai[tools]"
# Start Docker containers
docker run -d --name praison-postgres -p 5432:5432 \
-e POSTGRES_PASSWORD=praison123 \
-e POSTGRES_DB=praisonai \
postgres:16
docker run -d --name praison-qdrant -p 6333:6333 qdrant/qdrant
docker run -d --name praison-redis -p 6379:6379 redis:7
```
## 1. Doctor Command - Validate Connectivity
```bash
# Check all stores
praisonai persistence doctor \
--conversation-url "postgresql://postgres:praison123@localhost:5432/praisonai" \
--knowledge-url "http://localhost:6333" \
--state-url "redis://localhost:6379"
```
**Expected Output:**
```
==================================================
PraisonAI Persistence Doctor
==================================================
[Conversation Store] Testing: postgresql://postgres:****@localhost:5432/praisonai
✅ Connected (postgres)
[Knowledge Store] Testing: http://localhost:6333
✅ Connected (qdrant)
[State Store] Testing: redis://localhost:6379
✅ Connected (redis)
==================================================
Results: 3/3 stores connected successfully
==================================================
```
## 2. Run Command - Execute Agent with Persistence
```bash
# Run agent with persistence (dry-run first)
praisonai persistence run \
--session-id "cli-demo-001" \
--conversation-url "postgresql://postgres:praison123@localhost:5432/praisonai" \
--dry-run \
"Hello, my name is Bob"
# Actually run it
praisonai persistence run \
--session-id "cli-demo-001" \
--conversation-url "postgresql://postgres:praison123@localhost:5432/praisonai" \
"Hello, my name is Bob"
```
**Expected Output:**
```
[Session: cli-demo-001]
Agent: Hello Bob! Nice to meet you. How can I help you today?
```
## 3. Resume Command - Continue a Session
```bash
# Show history
praisonai persistence resume \
--session-id "cli-demo-001" \
--conversation-url "postgresql://postgres:praison123@localhost:5432/praisonai" \
--show-history
# Continue conversation
praisonai persistence resume \
--session-id "cli-demo-001" \
--conversation-url "postgresql://postgres:praison123@localhost:5432/praisonai" \
--continue "What's my name?"
```
**Expected Output:**
```
[Session: cli-demo-001]
Messages in history: 2
--- Conversation History ---
[USER] Hello, my name is Bob
[ASSISTANT] Hello Bob! Nice to meet you...
--- End History ---
Agent: Your name is Bob!
```
## Environment Variables
Instead of passing URLs on command line, use environment variables:
```bash
export PRAISON_CONVERSATION_URL="postgresql://postgres:praison123@localhost:5432/praisonai"
export PRAISON_KNOWLEDGE_URL="http://localhost:6333"
export PRAISON_STATE_URL="redis://localhost:6379"
export OPENAI_API_KEY="your-key"
# Now commands are simpler
praisonai persistence doctor --all
praisonai persistence run --session-id "my-session" "Hello!"
```
## Full CLI Reference
```
praisonai persistence --help
praisonai persistence doctor --help
praisonai persistence run --help
praisonai persistence resume --help
```
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/env python3
"""
Basic Context Compaction Example for PraisonAI Agents.
This example demonstrates how to use context compaction to:
1. Manage conversation context length
2. Use different compaction strategies
3. Track compaction results
4. Preserve important messages
Usage:
python basic_compaction.py
"""
from praisonaiagents.compaction import (
ContextCompactor, CompactionConfig, CompactionStrategy, CompactionResult
)
def main():
print("=" * 60)
print("Context Compaction Demo")
print("=" * 60)
# ==========================================================================
# Sample Messages
# ==========================================================================
messages = [
{"role": "system", "content": "You are a helpful AI assistant."},
{"role": "user", "content": "Hello! Can you help me with Python?"},
{"role": "assistant", "content": "Of course! I'd be happy to help you with Python. What would you like to know?"},
{"role": "user", "content": "How do I read a file in Python?"},
{"role": "assistant", "content": "To read a file in Python, you can use the built-in open() function. Here's an example:\n\nwith open('filename.txt', 'r') as f:\n content = f.read()\n\nThis opens the file, reads its content, and automatically closes it."},
{"role": "user", "content": "What about writing to a file?"},
{"role": "assistant", "content": "To write to a file, use the 'w' mode:\n\nwith open('filename.txt', 'w') as f:\n f.write('Hello, World!')\n\nUse 'a' mode to append instead of overwriting."},
{"role": "user", "content": "Can you explain list comprehensions?"},
{"role": "assistant", "content": "List comprehensions are a concise way to create lists. Instead of:\n\nresult = []\nfor x in range(10):\n result.append(x * 2)\n\nYou can write:\n\nresult = [x * 2 for x in range(10)]"},
]
print(f"\n--- Original Messages ---")
print(f" Message count: {len(messages)}")
# ==========================================================================
# Basic Compaction
# ==========================================================================
print("\n--- Basic Compaction (Truncate Strategy) ---")
compactor = ContextCompactor(
max_tokens=50, # Low limit to trigger compaction
strategy=CompactionStrategy.TRUNCATE,
preserve_system=True,
preserve_recent=2
)
# Check stats before
stats = compactor.get_stats(messages)
print(f" Total tokens: {stats['total_tokens']}")
print(f" Max tokens: {stats['max_tokens']}")
print(f" Needs compaction: {stats['needs_compaction']}")
# Compact
compacted, result = compactor.compact(messages)
print(f"\n After compaction:")
print(f" Messages: {len(messages)} -> {len(compacted)}")
print(f" Tokens: {result.original_tokens} -> {result.compacted_tokens}")
print(f" Saved: {result.tokens_saved} tokens")
print(f" Compression: {result.compression_ratio:.1%}")
# ==========================================================================
# Sliding Window Strategy
# ==========================================================================
print("\n--- Sliding Window Strategy ---")
compactor = ContextCompactor(
max_tokens=50,
strategy=CompactionStrategy.SLIDING,
preserve_system=True,
preserve_recent=3
)
compacted, result = compactor.compact(messages)
print(f" Messages kept: {result.messages_kept}")
print(f" Messages removed: {result.messages_removed}")
print(f" Strategy: {result.strategy_used.value}")
# ==========================================================================
# Summarize Strategy
# ==========================================================================
print("\n--- Summarize Strategy ---")
compactor = ContextCompactor(
max_tokens=50,
strategy=CompactionStrategy.SUMMARIZE,
preserve_system=True,
preserve_recent=2
)
compacted, result = compactor.compact(messages)
print(f" Messages kept: {result.messages_kept}")
print(f" Strategy: {result.strategy_used.value}")
# Show what messages remain
print(f"\n Remaining message roles:")
for msg in compacted:
role = msg.get("role", "unknown")
content_preview = msg.get("content", "")[:50]
print(f" [{role}] {content_preview}...")
# ==========================================================================
# No Compaction Needed
# ==========================================================================
print("\n--- No Compaction Needed ---")
compactor = ContextCompactor(
max_tokens=10000, # High limit
strategy=CompactionStrategy.TRUNCATE
)
compacted, result = compactor.compact(messages)
print(f" Was compacted: {result.was_compacted}")
print(f" Messages unchanged: {len(compacted) == len(messages)}")
# ==========================================================================
# Result Serialization
# ==========================================================================
print("\n--- Result Serialization ---")
compactor = ContextCompactor(max_tokens=50)
_, result = compactor.compact(messages)
data = result.to_dict()
print(f" Original tokens: {data['original_tokens']}")
print(f" Compacted tokens: {data['compacted_tokens']}")
print(f" Compression ratio: {data['compression_ratio']:.2f}")
print("\n" + "=" * 60)
print("Demo Complete!")
print("=" * 60)
if __name__ == "__main__":
main()
+85
View File
@@ -0,0 +1,85 @@
"""
CLI Compare Example - Advanced Usage
This example demonstrates advanced comparison features including
custom mode configurations and result analysis.
"""
from praisonai.cli.features.compare import (
CompareHandler,
CompareResult,
ModeResult,
get_mode_config,
save_compare_result,
format_comparison_table,
)
# Create custom mode configurations
custom_modes = {
"fast": {"llm": "gpt-4o-mini"},
"accurate": {"llm": "gpt-4o", "planning": True},
"research": {"research": True, "web_search": True},
}
# Create handler with verbose output
handler = CompareHandler(verbose=True)
# Example: Manually create comparison results for analysis
# (useful for testing without API calls)
mock_result = CompareResult(
query="What are the latest AI trends?",
comparisons=[
ModeResult(
mode="basic",
output="AI trends include LLMs, multimodal models, and agents.",
execution_time_ms=1234.5,
model_used="gpt-4o-mini",
tools_used=[]
),
ModeResult(
mode="tools",
output="Based on recent search results, AI trends in 2024 include...",
execution_time_ms=2567.8,
model_used="gpt-4o-mini",
tools_used=["internet_search"]
),
ModeResult(
mode="research",
output="Comprehensive research shows that AI trends...",
execution_time_ms=5432.1,
model_used="gpt-4o-mini",
tools_used=["internet_search", "web_scraper"]
),
]
)
# Get summary statistics
summary = mock_result.get_summary()
print("Comparison Summary:")
print(f" Fastest mode: {summary['fastest']} ({summary['fastest_time_ms']:.1f}ms)")
print(f" Slowest mode: {summary['slowest']} ({summary['slowest_time_ms']:.1f}ms)")
# Format as table
print("\n" + format_comparison_table(mock_result))
# Convert to JSON for storage
print("\nJSON Output:")
print(mock_result.to_json())
# Save to file
# save_compare_result(mock_result, "advanced_comparison.json")
print("\n--- CLI Usage Examples ---")
print("""
# Basic comparison
praisonai "What is AI?" --compare "basic,tools"
# Compare with specific model
praisonai "Explain quantum computing" --compare "basic,planning,research" --model gpt-4o
# Save results to file
praisonai "Latest tech news" --compare "basic,tools,web_search" --compare-output results.json
# Verbose output
praisonai "Write a poem" --compare "basic,planning" --verbose
""")
+45
View File
@@ -0,0 +1,45 @@
"""
CLI Compare Example - Basic Usage
This example demonstrates how to compare different CLI modes programmatically.
"""
from praisonai.cli.features.compare import (
CompareHandler,
get_mode_config,
list_available_modes,
parse_modes,
)
# List all available comparison modes
print("Available modes:")
for mode in list_available_modes():
config = get_mode_config(mode)
print(f" - {mode}: {config}")
# Parse modes from comma-separated string
modes = parse_modes("basic,tools,planning")
print(f"\nParsed modes: {modes}")
# Create compare handler
handler = CompareHandler(verbose=True)
# Compare modes (this will run actual agent calls)
# Uncomment to run:
# result = handler.compare(
# query="What is artificial intelligence?",
# modes=["basic", "tools"],
# model="gpt-4o-mini"
# )
# handler.print_result(result)
# Save results to file
# result = handler.execute(
# query="Explain machine learning",
# modes_str="basic,planning",
# output_path="comparison_results.json"
# )
print("\nTo run comparison via CLI:")
print(' praisonai "What is AI?" --compare "basic,tools,planning"')
print(' praisonai "What is AI?" --compare "basic,research" --compare-output results.json')
@@ -0,0 +1,23 @@
# Example: Data Collection Agent with 30-minute Schedule
# Collects and analyzes data every 30 minutes
framework: praisonai
agents:
- name: "Data Collector"
role: "Data Analysis Specialist"
goal: "Collect and analyze market data at regular intervals"
instructions: |
You are a data analysis specialist focused on collecting and analyzing
market trends and metrics. Provide actionable insights from the data.
tools:
- search_tool
verbose: false
task: "Collect latest market data and identify key trends"
# Schedule: Every 30 minutes with immediate execution
schedule:
interval: "*/30m"
max_retries: 5
run_immediately: true
@@ -0,0 +1,53 @@
# Example: 24/7 AI News Monitor with Scheduler
# This agent runs continuously at regular intervals to monitor AI news
framework: praisonai
agents:
- name: "AI News Monitor"
role: "Technology News Analyst"
goal: "Monitor and summarize the latest AI developments"
instructions: |
You are an expert technology news analyst specializing in AI and machine learning.
Your job is to search for the latest AI news, identify the most important developments,
and provide clear, concise summaries with sources.
Focus on:
- Major AI product launches
- Research breakthroughs
- Industry trends
- Policy and regulation updates
tools:
- search_tool
verbose: true
# Task to execute on each scheduled run
task: |
Search for the latest AI news from the past 24 hours.
Provide the top 3 most important stories with:
1. Headline
2. Brief summary (2-3 sentences)
3. Source URL
4. Why it's significant
# Schedule configuration
schedule:
# Interval options:
# - "hourly" - Every hour
# - "daily" - Every 24 hours
# - "*/30m" - Every 30 minutes
# - "*/6h" - Every 6 hours
# - "3600" - Custom seconds
interval: "hourly"
# Maximum retry attempts if execution fails
max_retries: 3
# Run immediately when scheduler starts (before first scheduled interval)
run_immediately: true
# Optional: Variables for customization
variables:
news_category: "AI and Machine Learning"
region: "Global"
time_range: "24 hours"
+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()
+69
View File
@@ -0,0 +1,69 @@
"""
Accuracy Evaluation Example
This example demonstrates how to evaluate agent output accuracy
by comparing against expected outputs using LLM-as-judge.
"""
import os
from praisonaiagents import Agent
from praisonaiagents.eval import AccuracyEvaluator
# Check if we have an API key
has_api_key = os.getenv("OPENAI_API_KEY") is not None
if has_api_key:
# Create a simple math tutor agent
agent = Agent(
instructions="You are a math tutor. Answer math questions concisely with just the number."
)
# Create accuracy evaluator
evaluator = AccuracyEvaluator(
agent=agent,
input_text="What is 2 + 2?",
expected_output="4",
num_iterations=3, # Run 3 times for statistical significance
verbose=True
)
# Run evaluation
result = evaluator.run(print_summary=True)
# Check results
print(f"\nAverage Score: {result.avg_score}/10")
print(f"Passed: {result.passed}")
else:
print("⚠️ No OPENAI_API_KEY found. Using mock evaluation...")
# Create evaluator without agent for mock testing
evaluator = AccuracyEvaluator(
func=lambda x: "4", # Mock function
input_text="What is 2 + 2?",
expected_output="4",
num_iterations=1,
verbose=True
)
# Test with mock output
try:
result = evaluator.run(print_summary=True)
print(f"\nMock Average Score: {result.avg_score}/10")
print(f"Mock Passed: {result.passed}")
except Exception as e:
print(f"Mock evaluation failed: {e}")
print("This is expected without an API key")
# You can also evaluate pre-generated outputs
print("\n--- Testing pre-generated output evaluation ---")
output = "The answer is 4"
if has_api_key:
try:
result2 = evaluator.evaluate_output(output, print_summary=True)
print(f"Pre-generated output score: {result2.avg_score}/10")
except Exception as e:
print(f"Pre-generated evaluation failed: {e}")
else:
print("⚠️ Skipping pre-generated evaluation (no API key)")
print("To run full evaluation, set OPENAI_API_KEY environment variable")
+105
View File
@@ -0,0 +1,105 @@
"""
Batch Evaluation Example
This example demonstrates how to run batch evaluations
from a JSON test file.
"""
import os
import json
import tempfile
from praisonaiagents.eval import AccuracyEvaluator
# Check if we have an API key
has_api_key = os.getenv("OPENAI_API_KEY") is not None
# Create a test file with multiple test cases
test_cases = [
{
"input": "What is 2 + 2?",
"expected": "4"
},
{
"input": "What is the capital of France?",
"expected": "Paris"
},
{
"input": "What color is the sky?",
"expected": "Blue"
}
]
# Save test cases to a temporary file
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
json.dump(test_cases, f)
test_file = f.name
print(f"Test file created: {test_file}")
print(f"Running {len(test_cases)} test cases...")
if has_api_key:
# You can use the CLI for batch evaluation:
# praisonai eval batch --agent agents.yaml --test-file tests.json --batch-type accuracy
# Or programmatically:
from praisonaiagents import Agent
agent = Agent(
instructions="You are a helpful assistant. Answer questions concisely."
)
results = []
for i, test_case in enumerate(test_cases):
print(f"\nTest {i + 1}: {test_case['input']}")
evaluator = AccuracyEvaluator(
agent=agent,
input_text=test_case["input"],
expected_output=test_case["expected"],
num_iterations=1
)
result = evaluator.run()
results.append({
"input": test_case["input"],
"expected": test_case["expected"],
"score": result.avg_score,
"passed": result.passed
})
print(f" Score: {result.avg_score}/10")
print(f" Passed: {result.passed}")
# Summary
passed = sum(1 for r in results if r["passed"])
print(f"\n{'='*50}")
print(f"Summary: {passed}/{len(results)} tests passed")
print(f"Pass Rate: {passed/len(results):.1%}")
else:
print("⚠️ No OPENAI_API_KEY found. Running mock batch evaluation...")
# Mock evaluation without API key
results = []
for i, test_case in enumerate(test_cases):
print(f"\nTest {i + 1}: {test_case['input']}")
# Mock result (all would fail without API key)
mock_score = 0.0
mock_passed = False
results.append({
"input": test_case["input"],
"expected": test_case["expected"],
"score": mock_score,
"passed": mock_passed
})
print(f" Score: {mock_score}/10 (mock)")
print(f" Passed: {mock_passed} (expected without API key)")
# Summary
passed = sum(1 for r in results if r["passed"])
print(f"\n{'='*50}")
print(f"Summary: {passed}/{len(results)} tests passed (mock evaluation)")
print(f"Pass Rate: {passed/len(results):.1%}")
print("\nTo run real batch evaluation, set OPENAI_API_KEY environment variable")
+82
View File
@@ -0,0 +1,82 @@
"""
Criteria Evaluation Example
This example demonstrates how to evaluate agent outputs
against custom criteria using LLM-as-judge.
"""
import os
from praisonaiagents import Agent
from praisonaiagents.eval import CriteriaEvaluator
# Check if we have an API key
has_api_key = os.getenv("OPENAI_API_KEY") is not None
if has_api_key:
print("--- Testing Criteria Evaluation with Agent ---")
# Create a customer service agent
agent = Agent(
instructions="You are a friendly customer service agent. Be helpful and empathetic."
)
# Create criteria evaluator with numeric scoring
evaluator = CriteriaEvaluator(
criteria="Response is helpful, empathetic, and provides a clear solution",
agent=agent,
input_text="I'm frustrated because my order hasn't arrived yet.",
scoring_type="numeric", # Score 1-10
threshold=7.0, # Pass if score >= 7
num_iterations=2,
verbose=True
)
# Run evaluation
result = evaluator.run(print_summary=True)
print("\nNumeric Scoring Results:")
print(f" Average Score: {result.avg_score}/10")
print(f" Pass Rate: {result.pass_rate:.1%}")
print(f" Passed: {result.passed}")
# Binary scoring example (pass/fail)
print("\n--- Testing Binary Scoring ---")
binary_evaluator = CriteriaEvaluator(
criteria="Response does not contain any offensive language",
agent=agent,
input_text="Tell me a joke",
scoring_type="binary", # Pass or Fail
verbose=True
)
binary_result = binary_evaluator.run(print_summary=True)
# With on_fail callback
print("\n--- Testing Failure Callback ---")
def handle_failure(score):
print(f"ALERT: Evaluation failed with score {score.score}")
print(f"Reasoning: {score.reasoning}")
callback_evaluator = CriteriaEvaluator(
criteria="Response is professional and helpful",
agent=agent,
input_text="Help me",
on_fail=handle_failure,
threshold=8.0
)
callback_evaluator.run()
else:
print("⚠️ No OPENAI_API_KEY found. Skipping agent-based criteria evaluation...")
# Test pre-generated output evaluation (doesn't need agent)
print("\n--- Testing Pre-generated Output Evaluation ---")
if has_api_key:
output = "I understand your frustration. Let me check on your order right away."
try:
result2 = evaluator.evaluate_output(output, print_summary=True)
print(f"Pre-generated output score: {result2.avg_score}/10")
except Exception as e:
print(f"Pre-generated evaluation failed: {e}")
else:
print("⚠️ Skipping pre-generated evaluation (no API key)")
print("To run full evaluation, set OPENAI_API_KEY environment variable")
+59
View File
@@ -0,0 +1,59 @@
"""
Performance Evaluation Example
This example demonstrates how to benchmark agent performance
by measuring runtime and memory usage across multiple iterations.
"""
import os
from praisonaiagents import Agent
from praisonaiagents.eval import PerformanceEvaluator
# Check if we have an API key
has_api_key = os.getenv("OPENAI_API_KEY") is not None
if has_api_key:
print("--- Testing Agent Performance ---")
# Create a simple agent
agent = Agent(
instructions="You are a helpful assistant. Answer questions briefly."
)
# Create performance evaluator
evaluator = PerformanceEvaluator(
agent=agent,
input_text="What is the capital of France?",
num_iterations=10, # Run 10 benchmark iterations
warmup_runs=2, # 2 warmup runs before measurement
track_memory=True, # Track memory usage
verbose=True
)
# Run evaluation
result = evaluator.run(print_summary=True)
# Access detailed metrics
print("\nAgent Performance Results:")
print(f" Average Time: {result.avg_run_time:.4f}s")
print(f" Min Time: {result.min_run_time:.4f}s")
print(f" Max Time: {result.max_run_time:.4f}s")
print(f" Median Time: {result.median_run_time:.4f}s")
print(f" P95 Time: {result.p95_run_time:.4f}s")
print(f" Avg Memory: {result.avg_memory:.2f} MB")
else:
print("⚠️ No OPENAI_API_KEY found. Skipping agent performance test...")
# You can also benchmark any function
def my_function():
import time
time.sleep(0.1)
return "done"
func_evaluator = PerformanceEvaluator(
func=my_function,
num_iterations=5,
warmup_runs=1,
track_memory=False
)
func_result = func_evaluator.run(print_summary=True)
+72
View File
@@ -0,0 +1,72 @@
"""
Reliability Evaluation Example
This example demonstrates how to verify that agents call
the expected tools during execution.
"""
import os
from praisonaiagents import Agent
from praisonaiagents.eval import ReliabilityEvaluator
def search_web(query: str) -> str:
"""Search the web for information."""
return f"Search results for: {query}"
def calculate(expression: str) -> str:
"""Calculate a math expression."""
return str(eval(expression))
# Check if we have an API key
has_api_key = os.getenv("OPENAI_API_KEY") is not None
if has_api_key:
print("--- Testing Agent Tool Call Reliability ---")
# Create an agent with tools
agent = Agent(
instructions="You are a helpful assistant with access to search and calculator tools.",
tools=[search_web, calculate]
)
# Create reliability evaluator
evaluator = ReliabilityEvaluator(
agent=agent,
input_text="Search for the weather in Paris and calculate 25 * 4",
expected_tools=["search_web", "calculate"], # Tools that should be called
forbidden_tools=["delete_file"], # Tools that should NOT be called
verbose=True
)
# Run evaluation
result = evaluator.run(print_summary=True)
# Check results
print("\nAgent Reliability Results:")
print(f" Passed: {result.passed}")
print(f" Pass Rate: {result.pass_rate:.1%}")
else:
print("⚠️ No OPENAI_API_KEY found. Skipping agent reliability test...")
print("Agent would fail to call tools without API key (expected behavior)")
# You can also evaluate pre-recorded tool calls (doesn't need API key)
print("\n--- Testing Pre-recorded Tool Call Evaluation ---")
# Create a mock agent for tool call evaluation
mock_agent = Agent(instructions="Mock agent")
evaluator = ReliabilityEvaluator(
agent=mock_agent,
expected_tools=["search_web", "calculate"], # Tools that should be called
forbidden_tools=["delete_file"], # Tools that should NOT be called
verbose=True
)
result2 = evaluator.evaluate_tool_calls(
actual_tools=["search_web", "calculate"],
print_summary=True
)
print("\nPre-recorded Tool Call Results:")
print(f" Passed: {result2.passed}")
print(f" Pass Rate: {result2.pass_rate:.1%}")
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Basic Hooks Example for PraisonAI Agents.
This example demonstrates how to use the hooks system to:
1. Log tool calls before execution
2. Block dangerous operations
3. Add context to agent responses
4. Monitor session lifecycle
Usage:
python basic_hooks.py
"""
import asyncio
from praisonaiagents import Agent
from praisonaiagents.hooks import (
HookRegistry, HookRunner, HookEvent, HookResult,
BeforeToolInput, AfterToolInput
)
def main():
# Create a hook registry
registry = HookRegistry()
# ==========================================================================
# Hook 1: Log all tool calls
# ==========================================================================
@registry.on(HookEvent.BEFORE_TOOL)
def log_tool_calls(event_data: BeforeToolInput) -> HookResult:
"""Log every tool call before execution."""
print(f"\n📝 [LOG] Tool: {event_data.tool_name}")
print(f" Input: {event_data.tool_input}")
return HookResult.allow()
# ==========================================================================
# Hook 2: Block dangerous file operations (using function logic)
# ==========================================================================
@registry.on(HookEvent.BEFORE_TOOL)
def block_delete_operations(event_data: BeforeToolInput) -> HookResult:
"""Block any delete or remove operations."""
dangerous_keywords = ['delete', 'remove', 'rm', 'unlink']
tool_lower = event_data.tool_name.lower()
if any(kw in tool_lower for kw in dangerous_keywords):
print(f"\n🚫 [BLOCKED] Dangerous operation: {event_data.tool_name}")
return HookResult.deny(
f"Operation '{event_data.tool_name}' is blocked by security policy"
)
return HookResult.allow()
# ==========================================================================
# Hook 3: Require confirmation for write operations
# ==========================================================================
@registry.on(HookEvent.BEFORE_TOOL)
def confirm_write_operations(event_data: BeforeToolInput) -> HookResult:
"""Request confirmation for write operations."""
write_keywords = ['write', 'save', 'create', 'update']
tool_lower = event_data.tool_name.lower()
if any(kw in tool_lower for kw in write_keywords):
print(f"\n⚠️ [CONFIRM] Write operation: {event_data.tool_name}")
# In a real scenario, you might prompt the user here
# For this example, we'll auto-approve
return HookResult.allow("Auto-approved for demo")
return HookResult.allow()
# ==========================================================================
# Hook 4: Add timing information after tool execution
# ==========================================================================
@registry.on(HookEvent.AFTER_TOOL)
def log_tool_completion(event_data: AfterToolInput) -> HookResult:
"""Log tool completion with timing."""
print(f"\n✅ [DONE] Tool: {event_data.tool_name}")
print(f" Duration: {event_data.execution_time_ms:.2f}ms")
if event_data.tool_error:
print(f" Error: {event_data.tool_error}")
return HookResult.allow()
# ==========================================================================
# Test the hooks
# ==========================================================================
print("=" * 60)
print("Testing Hooks System")
print("=" * 60)
runner = HookRunner(registry)
# Test 1: Normal tool call (should be logged and allowed)
print("\n--- Test 1: Normal read operation ---")
input1 = BeforeToolInput(
session_id="test",
cwd="/tmp",
event_name="before_tool",
timestamp="2024-01-01T00:00:00",
tool_name="read_file",
tool_input={"path": "/tmp/test.txt"}
)
results = asyncio.run(runner.execute(HookEvent.BEFORE_TOOL, input1))
print(f"Result: {'ALLOWED' if not HookRunner.is_blocked(results) else 'BLOCKED'}")
# Test 2: Delete operation (should be blocked)
print("\n--- Test 2: Delete operation ---")
input2 = BeforeToolInput(
session_id="test",
cwd="/tmp",
event_name="before_tool",
timestamp="2024-01-01T00:00:00",
tool_name="delete_file",
tool_input={"path": "/important/data.txt"}
)
results = asyncio.run(runner.execute(HookEvent.BEFORE_TOOL, input2))
print(f"Result: {'ALLOWED' if not HookRunner.is_blocked(results) else 'BLOCKED'}")
if HookRunner.is_blocked(results):
print(f"Reason: {HookRunner.get_blocking_reason(results)}")
# Test 3: Write operation (should be confirmed)
print("\n--- Test 3: Write operation ---")
input3 = BeforeToolInput(
session_id="test",
cwd="/tmp",
event_name="before_tool",
timestamp="2024-01-01T00:00:00",
tool_name="write_file",
tool_input={"path": "/tmp/output.txt", "content": "Hello"}
)
results = asyncio.run(runner.execute(HookEvent.BEFORE_TOOL, input3))
print(f"Result: {'ALLOWED' if not HookRunner.is_blocked(results) else 'BLOCKED'}")
# Show registered hooks
print("\n" + "=" * 60)
print("Registered Hooks:")
print("=" * 60)
for event, hooks in registry.list_hooks().items():
print(f"\n{event}:")
for hook in hooks:
print(f" - {hook['name']} (matcher: {hook['matcher'] or '*'})")
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);
+55
View File
@@ -0,0 +1,55 @@
"""
Basic Middleware Example - PraisonAI Agents
Demonstrates before/after hooks and wrap decorators for model and tool calls.
"""
from praisonaiagents import Agent, tool
from praisonaiagents.hooks import (
before_model, after_model, wrap_model_call,
before_tool, after_tool, wrap_tool_call,
InvocationContext, ModelRequest, ModelResponse
)
# Simple tool for demonstration
@tool
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Sunny, 22°C in {city}"
# Before model hook - adds context
@before_model
def add_context(request: ModelRequest) -> ModelRequest:
print(f"[before_model] Adding context to request")
return request
# After model hook - logs response
@after_model
def log_response(response: ModelResponse) -> ModelResponse:
print(f"[after_model] Response received")
return response
# Wrap tool call - retry on error
@wrap_tool_call
def retry_on_error(tool_call, call_next):
print(f"[wrap_tool_call] Executing tool")
try:
return call_next(tool_call)
except Exception as e:
print(f"[wrap_tool_call] Retrying after error: {e}")
return call_next(tool_call)
# Create agent with hooks
agent = Agent(
name="WeatherBot",
instructions="You help with weather queries.",
tools=[get_weather],
hooks=[add_context, log_response, retry_on_error]
)
if __name__ == "__main__":
# Test the tool directly
result = get_weather("London")
print(f"Weather: {result}")
print("\n✓ Middleware example complete")
+31
View File
@@ -0,0 +1,31 @@
"""
Configurable Model Example - PraisonAI Agents
Demonstrates runtime model switching without recreating the agent.
"""
from praisonaiagents import Agent
# Create agent with configurable model enabled
agent = Agent(
name="FlexBot",
instructions="You are a helpful assistant.",
llm="gpt-4o-mini",
llm_config={"configurable": True}
)
if __name__ == "__main__":
# Default model call
print("Using default model (gpt-4o-mini)...")
# response = agent.chat("Say hello in 5 words")
# Override model per-call
print("\nOverriding to different model...")
# response = agent.chat("Say hello in 5 words", config={"model": "gpt-4o"})
# Override temperature
print("\nOverriding temperature...")
# response = agent.chat("Say hello creatively", config={"temperature": 0.9})
print("\n✓ Configurable model example complete")
print("Note: Uncomment agent.chat() calls to run with API key")
+50
View File
@@ -0,0 +1,50 @@
"""
Injected State Example - PraisonAI Agents
Demonstrates injecting agent state into tools without exposing it in the schema.
"""
from praisonaiagents import Agent, tool
from praisonaiagents.tools import Injected
from praisonaiagents.tools.injected import AgentState, with_injection_context
# Tool with injected state - state param is NOT in the public schema
@tool
def show_context(query: str, state: Injected[dict]) -> str:
"""Show the current agent context."""
session_id = state.get('session_id', 'unknown')
agent_id = state.get('agent_id', 'unknown')
return f"Query: {query}, Session: {session_id}, Agent: {agent_id}"
# Create agent with the tool
agent = Agent(
name="ContextBot",
instructions="You help show context information.",
tools=[show_context],
session_id="my-session-123"
)
if __name__ == "__main__":
# Verify injected param is not in schema
schema = show_context.get_schema()
params = schema['function']['parameters']['properties']
print(f"Schema params: {list(params.keys())}")
assert 'state' not in params, "state should NOT be in schema"
print("✓ 'state' correctly excluded from schema")
# Test with manual injection context
mock_state = AgentState(
agent_id="test-agent",
run_id="run-1",
session_id="session-abc"
)
with with_injection_context(mock_state):
result = show_context(query="hello")
print(f"Result: {result}")
# Test via agent.execute_tool
result = agent.execute_tool("show_context", {"query": "test"})
print(f"Agent result: {result}")
print("\n✓ Injected state example complete")
+29
View File
@@ -0,0 +1,29 @@
"""
Rate Limiter Example - PraisonAI Agents
Demonstrates token bucket rate limiting for LLM API calls.
"""
from praisonaiagents import Agent
from praisonaiagents.llm import RateLimiter
# Create rate limiter: 60 requests per minute
limiter = RateLimiter(requests_per_minute=60, burst=5)
# Create agent with rate limiter
agent = Agent(
name="RateLimitedBot",
instructions="You are a helpful assistant.",
rate_limiter=limiter
)
if __name__ == "__main__":
print(f"Rate limiter: {limiter}")
print(f"Available tokens: {limiter.available_tokens}")
# Demonstrate rate limiting
for i in range(3):
limiter.acquire()
print(f"Request {i+1} acquired, tokens left: {limiter.available_tokens:.1f}")
print("\n✓ Rate limiter example complete")
@@ -0,0 +1,122 @@
"""
Multi-Agent Persistence Example
Demonstrates how multiple agents can share or isolate conversation
history using the persistence layer.
"""
from praisonai.persistence.factory import create_conversation_store, create_state_store
from praisonai.persistence.conversation.base import ConversationSession, ConversationMessage
import uuid
def main():
# Create stores
conv_store = create_conversation_store("sqlite", path=":memory:")
state_store = create_state_store("memory")
print("=== Multi-Agent Persistence Demo ===\n")
# Scenario 1: Shared session (agents collaborate)
print("--- Scenario 1: Shared Session ---")
shared_session_id = f"shared-{uuid.uuid4().hex[:8]}"
session = ConversationSession(
session_id=shared_session_id,
user_id="user-123",
name="Shared Conversation"
)
conv_store.create_session(session)
# Agent 1 (Researcher) adds context
conv_store.add_message(shared_session_id, ConversationMessage(
role="assistant",
content="[Researcher] I found relevant information about the topic.",
metadata={"agent_id": "researcher", "agent_role": "research"}
))
# Agent 2 (Writer) uses the context
conv_store.add_message(shared_session_id, ConversationMessage(
role="assistant",
content="[Writer] Based on the research, here's a summary...",
metadata={"agent_id": "writer", "agent_role": "writing"}
))
# Agent 3 (Editor) reviews
conv_store.add_message(shared_session_id, ConversationMessage(
role="assistant",
content="[Editor] I've reviewed and polished the content.",
metadata={"agent_id": "editor", "agent_role": "editing"}
))
messages = conv_store.get_messages(shared_session_id)
print(f"Shared session has {len(messages)} messages from different agents")
for msg in messages:
agent = msg.metadata.get("agent_id", "unknown") if msg.metadata else "unknown"
print(f" - {agent}: {msg.content[:50]}...")
# Scenario 2: Isolated sessions (agents work independently)
print("\n--- Scenario 2: Isolated Sessions ---")
agent_sessions = {}
for agent_name in ["planner", "executor", "validator"]:
session_id = f"{agent_name}-{uuid.uuid4().hex[:8]}"
agent_sessions[agent_name] = session_id
conv_store.create_session(ConversationSession(
session_id=session_id,
agent_id=agent_name,
name=f"{agent_name.title()} Session"
))
# Each agent has its own conversation
conv_store.add_message(session_id, ConversationMessage(
role="user",
content=f"Task for {agent_name}"
))
conv_store.add_message(session_id, ConversationMessage(
role="assistant",
content=f"[{agent_name.title()}] Processing task..."
))
print("Created isolated sessions for each agent:")
for agent, sid in agent_sessions.items():
msgs = conv_store.get_messages(sid)
print(f" - {agent}: {len(msgs)} messages")
# Scenario 3: Shared state across agents
print("\n--- Scenario 3: Shared State ---")
# Agents share state for coordination
state_store.set("workflow:status", {"phase": "research", "progress": 0})
state_store.set("workflow:context", {"topic": "AI Agents", "deadline": "2024-12-31"})
# Agent 1 updates progress
state = state_store.get("workflow:status")
state["progress"] = 33
state["phase"] = "writing"
state_store.set("workflow:status", state)
print(f"Agent 1 updated state: {state}")
# Agent 2 reads and updates
state = state_store.get("workflow:status")
state["progress"] = 66
state["phase"] = "editing"
state_store.set("workflow:status", state)
print(f"Agent 2 updated state: {state}")
# Agent 3 completes
state = state_store.get("workflow:status")
state["progress"] = 100
state["phase"] = "complete"
state_store.set("workflow:status", state)
print(f"Agent 3 completed: {state}")
# Cleanup
conv_store.close()
state_store.close()
print("\n✅ Multi-agent persistence demo complete!")
if __name__ == "__main__":
main()
+40
View File
@@ -0,0 +1,40 @@
"""Multi-Agent Shared Session - DB Persistence Test"""
import sys
sys.path.insert(0, 'src/praisonai')
from praisonai.persistence import create_conversation_store
from praisonai.persistence.conversation.base import ConversationSession, ConversationMessage
# Create shared session for multiple agents
store = create_conversation_store("sqlite", path="/tmp/multi_agent.db")
session_id = "shared-session-123"
# Create session
session = ConversationSession(session_id=session_id, agent_id="multi")
try:
store.create_session(session)
except Exception:
pass
# Agent 1 writes
msg1 = ConversationMessage(session_id=session_id, role="user", content="Agent1: Hello")
store.add_message(session_id, msg1)
msg2 = ConversationMessage(session_id=session_id, role="assistant", content="Agent1: Hi there!")
store.add_message(session_id, msg2)
# Agent 2 writes to same session
msg3 = ConversationMessage(session_id=session_id, role="user", content="Agent2: What did Agent1 say?")
store.add_message(session_id, msg3)
msg4 = ConversationMessage(session_id=session_id, role="assistant", content="Agent2: Agent1 said Hello")
store.add_message(session_id, msg4)
# Verify both agents' messages are in session
messages = store.get_messages(session_id)
print(f"Total messages in shared session: {len(messages)}")
assert len(messages) >= 4, "Should have messages from both agents"
# Verify content
contents = [m.content for m in messages]
assert any("Agent1" in c for c in contents), "Should have Agent1 messages"
assert any("Agent2" in c for c in contents), "Should have Agent2 messages"
print("PASSED: Multi-agent shared session persistence")
@@ -0,0 +1,16 @@
"""Multi-Agent Shared Session Demo"""
from praisonaiagents import Agent
from praisonai.persistence import create_conversation_store
store = create_conversation_store("sqlite", path="/tmp/multi_agent.db")
agent1 = Agent(name="Researcher", llm="gpt-4o-mini", db=store, session_id="shared-session")
agent2 = Agent(name="Writer", llm="gpt-4o-mini", db=store, session_id="shared-session")
r1 = agent1.chat("Research topic: AI in healthcare. Key finding: reduces diagnosis time by 50%")
print(f"Researcher: {r1[:50]}...")
r2 = agent2.chat("Based on the research, what was the key finding?")
print(f"Writer: {r2[:50]}...")
assert "50" in r2 or "diagnosis" in r2.lower(), "Writer should see Researcher's context"
print("PASSED: Multi-agent shared session works")
+48
View File
@@ -0,0 +1,48 @@
"""
Basic Observability Usage Example
This example demonstrates how to use the observability module
with PraisonAI agents.
Usage:
# Set your provider's API key first
export LANGFUSE_PUBLIC_KEY=pk-lf-xxx
export LANGFUSE_SECRET_KEY=sk-lf-xxx
python basic_usage.py
"""
from praisonai_tools.observability import obs
from praisonaiagents import Agent
# Initialize observability (auto-detects provider from env vars)
obs.init()
# Or specify a provider explicitly
# obs.init(provider="langfuse", project_name="my-project")
# Create an agent
agent = Agent(
instructions="You are a helpful assistant.",
model="gpt-4o-mini",
)
# Use trace context manager for complete workflow tracing
with obs.trace("chat-session", session_id="user-123"):
# Use span context manager for individual operations
with obs.span("user-query", kind=obs.SpanKind.AGENT):
response = agent.chat("What is the capital of France?")
print(response)
# Log LLM calls manually if needed
obs.log_llm_call(
model="gpt-4o-mini",
input_messages="What is 2+2?",
output="4",
input_tokens=10,
output_tokens=1,
)
# Check diagnostics
print("\nDiagnostics:")
print(obs.doctor())
@@ -0,0 +1,48 @@
"""
Langfuse Integration Example
This example shows how to use Langfuse for LLM observability.
Setup:
1. Sign up at https://langfuse.com/
2. Get your API keys from the project settings
3. Set environment variables:
export LANGFUSE_PUBLIC_KEY=pk-lf-xxx
export LANGFUSE_SECRET_KEY=sk-lf-xxx
4. Install dependencies:
pip install opentelemetry-sdk opentelemetry-exporter-otlp
Usage:
python langfuse_example.py
"""
import os
from praisonai_tools.observability import obs
from praisonaiagents import Agent
# Initialize Langfuse
success = obs.init(
provider="langfuse",
project_name="praisonai-demo",
)
if not success:
print("Failed to initialize Langfuse. Check your API keys.")
print("Required: LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY")
exit(1)
print("Langfuse initialized successfully!")
print(f"View traces at: https://cloud.langfuse.com/")
# Create agent
agent = Agent(
instructions="You are a helpful coding assistant.",
model="gpt-4o-mini",
)
# Run with tracing
with obs.trace("coding-session", user_id="developer-1"):
response = agent.chat("Write a Python function to calculate fibonacci numbers")
print(response)
print("\nCheck Langfuse dashboard for traces!")
@@ -0,0 +1,22 @@
"""MLflow Local Observability Demo (no API key needed)"""
import mlflow
import time
mlflow.set_tracking_uri("file:///tmp/mlflow_demo")
mlflow.set_experiment("praisonai-demo")
with mlflow.start_run(run_name="agent-trace"):
mlflow.log_param("agent_name", "Assistant")
mlflow.log_param("model", "gpt-4o-mini")
# Simulate agent work
start = time.time()
time.sleep(0.1)
latency = time.time() - start
mlflow.log_metric("latency_ms", latency * 1000)
mlflow.log_metric("tokens_used", 150)
print(f"Logged run to MLflow: latency={latency*1000:.1f}ms")
print("PASSED: MLflow local observability works")
@@ -0,0 +1,53 @@
"""
Multi-Agent Tracing Example
This example shows how to trace multi-agent workflows with
parent/child span relationships.
Usage:
# Set your provider's API key
export LANGFUSE_PUBLIC_KEY=pk-lf-xxx
export LANGFUSE_SECRET_KEY=sk-lf-xxx
python multi_agent_tracing.py
"""
from praisonai_tools.observability import obs
from praisonai_tools.observability.base import SpanKind
from praisonaiagents import Agent, PraisonAIAgents
# Initialize observability
obs.init()
# Create agents
researcher = Agent(
name="Researcher",
instructions="You research topics and provide detailed information.",
model="gpt-4o-mini",
)
writer = Agent(
name="Writer",
instructions="You write clear, engaging content based on research.",
model="gpt-4o-mini",
)
# Trace the multi-agent workflow
with obs.trace("content-creation", metadata={"workflow": "research-write"}):
# Research phase
with obs.span("research-phase", kind=SpanKind.AGENT) as research_span:
research_span.attributes["agent"] = "Researcher"
research_result = researcher.chat("Research the benefits of AI in healthcare")
# Writing phase
with obs.span("writing-phase", kind=SpanKind.AGENT) as write_span:
write_span.attributes["agent"] = "Writer"
write_span.attributes["input_length"] = len(str(research_result))
final_content = writer.chat(f"Write a blog post based on: {research_result}")
print("Final Content:")
print(final_content)
# Check trace info
print("\nDiagnostics:", obs.doctor())
+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!")
+71
View File
@@ -0,0 +1,71 @@
"""
Qdrant Knowledge Store - Agent-First Example
Demonstrates using Qdrant for knowledge-based RAG with an Agent.
Requirements:
pip install "praisonai[tools]"
Docker Setup:
docker run -d --name praison-qdrant -p 6333:6333 qdrant/qdrant
Run:
python knowledge_qdrant.py
Expected Output:
Agent responds using knowledge from documents
"""
from praisonaiagents import Agent
import tempfile
import os
import shutil
# Create sample knowledge document
sample_doc = """
# AI and Programming Guide
## Python Programming
Python is a versatile programming language used for web development, data science, and AI.
It has a simple syntax and extensive libraries.
## Machine Learning
Machine learning enables computers to learn patterns from data without explicit programming.
Common frameworks include TensorFlow, PyTorch, and scikit-learn.
## Databases
PostgreSQL is a powerful open-source relational database system.
It supports both SQL and JSON data types.
"""
# Save to temp file
temp_dir = tempfile.mkdtemp()
doc_path = os.path.join(temp_dir, "guide.txt")
with open(doc_path, "w") as f:
f.write(sample_doc)
print("=== Qdrant Knowledge Store Demo (Agent-First) ===")
# Agent-first approach: use knowledge parameter with Qdrant
agent = Agent(
name="KnowledgeAssistant",
instructions="You are a helpful assistant with access to technical documentation.",
knowledge=[doc_path],
knowledge_config={
"vector_store": "qdrant",
"url": "http://localhost:6333"
}
)
# Chat - agent uses knowledge for RAG
response = agent.chat("What programming language is good for AI?")
print(f"Response: {response}")
# Cleanup
shutil.rmtree(temp_dir)
print("\n=== Demo Complete ===")
# --- Advanced: Direct Store Usage ---
# from praisonai.persistence.factory import create_knowledge_store
# store = create_knowledge_store("qdrant", url="http://localhost:6333")
+43
View File
@@ -0,0 +1,43 @@
"""
Minimal Agent with Database Persistence
This is the simplest way to add persistence to your agent.
Messages, runs, and traces are automatically saved.
Run:
python minimal_agent_db.py
Expected output:
- Agent responds to your question
- Data is persisted to PostgreSQL
- Session can be resumed later with same session_id
"""
from praisonaiagents import Agent, db
# Create database connection (PostgreSQL + Redis)
my_db = db(
database_url="postgresql://postgres:praison123@localhost:5432/praisonai",
state_url="redis://localhost:6379" # Optional: for state/tracing
)
# Create agent with persistence
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant. Be concise.",
db=my_db,
# session_id is optional - defaults to per-hour ID (YYYYMMDDHH-hash)
# Set explicitly for session continuity across runs:
session_id="my-persistent-session"
)
# Chat - messages are automatically persisted
response = agent.chat("What is the capital of France?")
print(f"Response: {response}")
# Verify persistence
data = my_db.export_session("my-persistent-session")
print(f"\nMessages stored: {len(data.get('messages', []))}")
# Clean up
my_db.close()
@@ -0,0 +1,61 @@
"""
PostgreSQL with Runs and Traces
Demonstrates full persistence with run tracking and tracing.
Run:
python postgres_runs_traces.py
Expected output:
- Agent responds with tool usage
- Runs and traces are persisted
- Export shows full session data
"""
from praisonaiagents import Agent, db
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Weather in {city}: Sunny, 72°F"
# Create database with PostgreSQL + Redis
my_db = db(
database_url="postgresql://postgres:praison123@localhost:5432/praisonai",
state_url="redis://localhost:6379"
)
# Create agent with tools
agent = Agent(
name="WeatherBot",
instructions="You help with weather. Use the get_weather tool when asked.",
tools=[get_weather],
db=my_db,
session_id="weather-session-001"
)
# First chat - triggers run tracking
print("=== First Question ===")
response1 = agent.chat("What's the weather in Tokyo?")
print(f"Response: {response1}\n")
# Second chat - same session, new run
print("=== Second Question ===")
response2 = agent.chat("How about New York?")
print(f"Response: {response2}\n")
# Export session data
print("=== Session Data ===")
data = my_db.export_session("weather-session-001")
print(f"Session ID: {data.get('session_id')}")
print(f"Messages: {len(data.get('messages', []))}")
print(f"Agent: {data.get('agent_name')}")
# Show messages
print("\n=== Messages ===")
for msg in data.get('messages', []):
role = msg.get('role', 'unknown')
content = msg.get('content', '')[:60]
print(f" [{role}] {content}...")
my_db.close()
print("\n✅ Done")
+46
View File
@@ -0,0 +1,46 @@
"""
Redis State Store - Agent-First Example
Use Redis for state management with an Agent.
Docker Setup:
docker run -d --name redis -p 6379:6379 redis:7
Run:
python redis_state.py
Expected output:
Agent responds with state persisted to Redis
"""
from praisonaiagents import Agent, db
print("=== Redis State Store (Agent-First) ===")
# Agent-first approach: use db parameter with Redis state store
my_db = db(
database_url="sqlite:///conversations.db", # Conversations
state_url="redis://localhost:6379" # State/tracing
)
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant.",
db=my_db,
session_id="redis-state-session"
)
# Chat - state is automatically managed via Redis
response = agent.chat("Hello! Remember my name is Alice.")
print(f"Response: {response}")
# Second message to test state
response2 = agent.chat("What is my name?")
print(f"Response: {response2}")
my_db.close()
print("\n✅ Done")
# --- Advanced: Direct Store Usage ---
# from praisonaiagents import db
# redis_db = db.RedisDB(host="localhost", port=6379)
+66
View File
@@ -0,0 +1,66 @@
"""
Session Resume Example
Demonstrates how to resume a conversation from a previous session.
Run:
python session_resume.py
Expected output:
- First run: Creates new session
- Second run: Resumes with history
"""
from praisonaiagents import Agent, db
# Create database
my_db = db(
database_url="postgresql://postgres:praison123@localhost:5432/praisonai",
state_url="redis://localhost:6379"
)
SESSION_ID = "resume-demo-session"
# Create agent with explicit session_id
agent = Agent(
name="MemoryBot",
instructions="You remember our conversation. Be helpful and concise.",
db=my_db,
session_id=SESSION_ID
)
# Check if this is a new or resumed session
data = my_db.export_session(SESSION_ID)
existing_messages = len(data.get('messages', []))
if existing_messages == 0:
print("=== NEW SESSION ===")
print("This is a new conversation.\n")
response = agent.chat("My name is Alice and I love Python programming.")
print(f"Response: {response}\n")
response = agent.chat("What's my favorite programming language?")
print(f"Response: {response}\n")
else:
print(f"=== RESUMED SESSION ({existing_messages} previous messages) ===")
print("Continuing previous conversation.\n")
# Show previous messages
print("Previous messages:")
for msg in data.get('messages', [])[:4]:
role = msg.get('role', 'unknown')
content = msg.get('content', '')[:60]
print(f" [{role}] {content}...")
print()
# Continue conversation
response = agent.chat("What's my name and what do I like?")
print(f"Response: {response}\n")
# Show final state
final_data = my_db.export_session(SESSION_ID)
print(f"Total messages now: {len(final_data.get('messages', []))}")
my_db.close()
print("✅ Done")
+58
View File
@@ -0,0 +1,58 @@
"""
Simple Database Persistence Example for PraisonAI Agents.
This example shows how to enable automatic conversation persistence
with just 2 lines of code.
Requirements:
pip install "praisonai[tools]"
Docker Setup:
docker run -d --name praison-postgres -p 5432:5432 \
-e POSTGRES_PASSWORD=praison123 \
-e POSTGRES_DB=praisonai \
postgres:16
Environment:
export OPENAI_API_KEY=your-key
Run:
python simple_agent_postgres.py
Expected Output:
=== First Run ===
Agent: Nice to meet you, Alice! Python is a great choice...
Session ID: demo-session-001
Messages persisted: 2
"""
from praisonaiagents import Agent, db
# Create database adapter (simplified import)
db_instance = db(
database_url="postgresql://postgres:praison123@localhost:5432/praisonai"
)
# Create agent with persistence enabled
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant. Keep responses brief.",
db=db_instance,
session_id="demo-session-001", # Same session_id = resume conversation
verbose=False
)
# Chat with persistence
print("=== First Run ===")
response = agent.chat("My name is Alice and I love Python programming.")
print(f"Agent: {response}\n")
# Show session info
print(f"Session ID: {agent.session_id}")
print(f"Messages in history: {len(agent.chat_history)}")
# Close DB connection
db_instance.close()
print("\n=== Session persisted! ===")
print("Run again with same session_id to resume.")
+41
View File
@@ -0,0 +1,41 @@
"""
SQLite Local Database
Use SQLite for simple local persistence without external services.
Run:
python sqlite_local.py
Expected output:
- Agent responds
- Data persisted to local SQLite file
"""
from praisonaiagents import Agent, db
import tempfile
import os
# Create SQLite database (local file)
db_path = os.path.join(tempfile.gettempdir(), "my_agent.db")
my_db = db.SQLiteDB(path=db_path)
print(f"Database: {db_path}")
# Create agent
agent = Agent(
name="LocalBot",
instructions="You are a helpful assistant.",
db=my_db,
session_id="local-session"
)
# Chat
response = agent.chat("Hello! What can you help me with?")
print(f"Response: {response}")
# Verify
data = my_db.export_session("local-session")
print(f"\nMessages stored: {len(data.get('messages', []))}")
my_db.close()
print("✅ Done")
+46
View File
@@ -0,0 +1,46 @@
"""
Redis State Store - Agent-First Example
Use Redis for state management with an Agent.
Docker Setup:
docker run -d --name praison-redis -p 6379:6379 redis:7
Run:
python state_redis.py
Expected Output:
Agent responds with state persisted to Redis
"""
from praisonaiagents import Agent, db
print("=== Redis State Store (Agent-First) ===")
# Agent-first approach: use db parameter with Redis state store
my_db = db(
database_url="sqlite:///conversations.db", # Conversations
state_url="redis://localhost:6379" # State/tracing
)
agent = Agent(
name="Assistant",
instructions="You are a helpful assistant.",
db=my_db,
session_id="redis-state-example"
)
# Chat - state is automatically managed via Redis
response = agent.chat("Hello! Remember my favorite color is blue.")
print(f"Response: {response}")
# Second message to test state
response2 = agent.chat("What is my favorite color?")
print(f"Response: {response2}")
my_db.close()
print("\n=== Demo Complete ===")
# --- Advanced: Direct Store Usage ---
# from praisonai.persistence.factory import create_state_store
# store = create_state_store("redis", url="redis://localhost:6379")
+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
```
+142
View File
@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Basic Policy Engine Example for PraisonAI Agents.
This example demonstrates how to use the policy engine to:
1. Create policies with rules
2. Check if actions are allowed
3. Block dangerous operations
4. Use convenience policy creators
Usage:
python basic_policy.py
"""
from praisonaiagents.policy import (
PolicyEngine, Policy, PolicyRule, PolicyAction, PolicyConfig,
create_deny_tools_policy, create_read_only_policy
)
def main():
print("=" * 60)
print("Policy Engine Demo")
print("=" * 60)
# Create a policy engine
engine = PolicyEngine()
# ==========================================================================
# Policy 1: Block dangerous tools
# ==========================================================================
print("\n--- Creating Policies ---")
dangerous_tools_policy = Policy(
name="block_dangerous",
description="Block dangerous file operations",
rules=[
PolicyRule(
action=PolicyAction.DENY,
resource="tool:delete_*",
reason="Delete operations are blocked",
name="deny_delete"
),
PolicyRule(
action=PolicyAction.DENY,
resource="tool:rm_*",
reason="Remove operations are blocked",
name="deny_rm"
),
],
priority=100
)
engine.add_policy(dangerous_tools_policy)
print(f"✅ Added policy: {dangerous_tools_policy.name}")
# ==========================================================================
# Policy 2: Allow read operations
# ==========================================================================
read_policy = Policy(
name="allow_read",
description="Allow read operations",
rules=[
PolicyRule(
action=PolicyAction.ALLOW,
resource="tool:read_*",
name="allow_read"
),
PolicyRule(
action=PolicyAction.ALLOW,
resource="tool:list_*",
name="allow_list"
),
]
)
engine.add_policy(read_policy)
print(f"✅ Added policy: {read_policy.name}")
# ==========================================================================
# Test policy checks
# ==========================================================================
print("\n--- Testing Policy Checks ---")
test_cases = [
("tool:read_file", "Reading a file"),
("tool:list_directory", "Listing directory"),
("tool:delete_file", "Deleting a file"),
("tool:rm_directory", "Removing directory"),
("tool:write_file", "Writing a file"),
]
for resource, description in test_cases:
result = engine.check(resource, {})
status = "✅ ALLOWED" if result.allowed else "🚫 DENIED"
reason = f" ({result.reason})" if result.reason else ""
print(f" {status}: {description}{reason}")
# ==========================================================================
# Using convenience functions
# ==========================================================================
print("\n--- Using Convenience Functions ---")
# Create a read-only policy
read_only = create_read_only_policy()
print(f"✅ Created read-only policy with {len(read_only.rules)} rules")
# Create a deny tools policy
deny_tools = create_deny_tools_policy(
["execute_*", "shell_*", "system_*"],
reason="System commands are blocked"
)
print(f"✅ Created deny-tools policy with {len(deny_tools.rules)} rules")
# ==========================================================================
# Strict mode example
# ==========================================================================
print("\n--- Strict Mode Example ---")
strict_engine = PolicyEngine(PolicyConfig(strict_mode=True))
# In strict mode, unknown resources are denied
result = strict_engine.check("tool:unknown_operation", {})
print(f" Unknown operation in strict mode: {'DENIED' if not result.allowed else 'ALLOWED'}")
# ==========================================================================
# Policy serialization
# ==========================================================================
print("\n--- Policy Serialization ---")
policy_dict = dangerous_tools_policy.to_dict()
print(f" Serialized policy: {policy_dict['name']} with {len(policy_dict['rules'])} rules")
# Recreate from dict
restored = Policy.from_dict(policy_dict)
print(f" Restored policy: {restored.name}")
print("\n" + "=" * 60)
print("Demo Complete!")
print("=" * 60)
if __name__ == "__main__":
main()
+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()
Loaded 100 of 830 files, more files were not shown because too many files have changed in this diff. Show more