Compare commits

...
1 Commits
Author SHA1 Message Date
Mervin Praison 8bf5a08246 Release v2.3.35 2025-12-18 16:28:02 +00:00
11 changed files with 79 additions and 111 deletions

No files matched your search

+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.34" \
"praisonai>=2.3.35" \
"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.34" \
"praisonai>=2.3.35" \
"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.34" \
"praisonai>=2.3.35" \
"praisonai[ui]" \
"praisonai[crewai]"
@@ -8,10 +8,12 @@ Tests single agent running a simple task across frameworks.
Usage:
export OPENAI_API_KEY=your_key
python benchmarks/execution_benchmark.py
python benchmarks/execution_benchmark.py --no-save
"""
import time
import os
import argparse
from importlib.metadata import version as get_version
# Check API key
@@ -220,6 +222,10 @@ def save_results(results: dict):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='PraisonAI Agents - Real Execution Benchmark')
parser.add_argument('--no-save', action='store_true', help='Do not save results to file')
args = parser.parse_args()
print('=' * 60)
print('PraisonAI Agents - Real Execution Benchmark')
print('=' * 60)
@@ -228,7 +234,7 @@ if __name__ == '__main__':
print(f'Prompt: "{PROMPT}"')
versions = get_package_versions()
print(f'\nPackage versions:')
print('\nPackage versions:')
for pkg, ver in versions.items():
print(f' {pkg}: {ver}')
@@ -273,6 +279,8 @@ if __name__ == '__main__':
print('\n' + '=' * 60)
# Save results
if results:
# Save results (unless --no-save)
if results and not args.no_save:
save_results(results)
elif args.no_save:
print('\nResults not saved (--no-save flag used)')
+3 -3
View File
@@ -33,7 +33,7 @@
"url": "http://127.0.0.1:8005/agents/researcher",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ query: $json.body?.query || $json.query || 'Research about Mars environment and cat behavior for the movie concept' } }) }}",
"jsonBody": "={{ JSON.stringify({ query: $json.body?.query || $json.query || 'Research about Mars environment and cat behavior for the movie concept' }) }}",
"options": {
"timeout": 300000
}
@@ -54,7 +54,7 @@
"url": "http://127.0.0.1:8005/agents/narrative_designer",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ query: $json.response || 'Create story concept based on research: {{previous_output}}' } }) }}",
"jsonBody": "={{ JSON.stringify({ query: $json.response || 'Create story concept based on research: previous_output' }) }}",
"options": {
"timeout": 300000
}
@@ -75,7 +75,7 @@
"url": "http://127.0.0.1:8005/agents/scriptwriter",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ query: $json.response || 'Write the final movie script based on the story concept: {{previous_output}}' } }) }}",
"jsonBody": "={{ JSON.stringify({ query: $json.response || 'Write the final movie script based on the story concept: previous_output' }) }}",
"options": {
"timeout": 300000
}
@@ -1,93 +0,0 @@
# Advanced Workflow Example
# Demonstrates: conditional routing, decision tasks, and multi-agent coordination
name: Content Creation Pipeline
description: A workflow that researches, writes, reviews, and publishes content
workflow:
process: workflow # Use workflow process for conditional execution
verbose: true
agents:
researcher:
name: Researcher
role: Research Specialist
goal: Gather comprehensive information on topics
backstory: Expert at finding and synthesizing information from various sources
instructions: |
Research the given topic thoroughly.
Provide detailed findings with key points.
llm: gpt-4o-mini
writer:
name: Writer
role: Content Writer
goal: Create engaging and informative content
backstory: Skilled writer who transforms research into readable content
instructions: |
Write clear, engaging content based on the research.
Structure the content with introduction, body, and conclusion.
llm: gpt-4o-mini
reviewer:
name: Reviewer
role: Quality Reviewer
goal: Ensure content meets quality standards
backstory: Meticulous editor who ensures accuracy and clarity
instructions: |
Review the content for accuracy, clarity, and engagement.
Decide if it's ready for publication or needs revision.
llm: gpt-4o-mini
publisher:
name: Publisher
role: Content Publisher
goal: Finalize and format content for publication
backstory: Expert at preparing content for various platforms
instructions: |
Format the approved content for publication.
Add metadata and prepare final deliverable.
llm: gpt-4o-mini
steps:
# Step 1: Research (starting point)
- name: research_task
agent: researcher
action: "Research the topic: AI trends in 2025"
expected_output: "Comprehensive research findings with key points and sources"
is_start: true
next_tasks: [write_task]
# Step 2: Write content based on research
- name: write_task
agent: writer
action: "Write an article based on the research findings"
expected_output: "Well-structured article with introduction, body, and conclusion"
context: [research_task]
next_tasks: [review_task]
# Step 3: Review with decision (conditional routing)
- name: review_task
agent: reviewer
action: "Review the article for quality and accuracy"
expected_output: "Quality assessment with approval or revision recommendation"
context: [write_task]
task_type: decision
condition:
approved: [publish_task]
needs_revision: [revise_task]
# Step 4a: Revision (conditional - only if review fails)
- name: revise_task
agent: writer
action: "Revise the article based on reviewer feedback"
expected_output: "Revised article addressing all feedback"
context: [write_task, review_task]
next_tasks: [review_task] # Loop back to review
# Step 4b: Publish (conditional - only if review passes)
- name: publish_task
agent: publisher
action: "Prepare the approved article for publication"
expected_output: "Final formatted article ready for publication"
context: [write_task, review_task]
+2 -2
View File
@@ -3,8 +3,8 @@ class Praisonai < Formula
desc "AI tools for various AI applications"
homepage "https://github.com/MervinPraison/PraisonAI"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.34.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.34.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.35.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.35.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
+5 -3
View File
@@ -412,12 +412,14 @@ class N8nHandler(FlagHandler):
agent_url_id = agent_id.lower().replace(' ', '_')
# Build the query - first agent uses webhook input, others use previous response
# Escape single quotes and double braces (n8n expression syntax)
escaped_action = action.replace("'", "\\'").replace("{{", "").replace("}}", "")
if is_first:
# First agent: use query from webhook body
query_expr = f"={{ $json.body?.query || $json.query || '{action}' }}"
query_expr = "$json.body?.query || $json.query || '" + escaped_action + "'"
else:
# Subsequent agents: use previous agent's response + original action context
query_expr = f"={{ $json.response || '{action}' }}"
query_expr = "$json.response || '" + escaped_action + "'"
return {
"id": f"agent_{index}",
@@ -430,7 +432,7 @@ class N8nHandler(FlagHandler):
"url": f"{self.praisonai_api_url}/agents/{agent_url_id}",
"sendBody": True,
"specifyBody": "json",
"jsonBody": f"={{{{ JSON.stringify({{ query: {query_expr[2:]} }}) }}}}",
"jsonBody": f"={{{{ JSON.stringify({{ query: {query_expr} }}) }}}}",
"options": {
"timeout": 300000 # 5 minute timeout per agent
}
+53 -2
View File
@@ -3060,6 +3060,11 @@ Now, {final_instruction.lower()}:"""
"""
Handle the serve command - start API server for agents.
Supports:
- Sequential workflows with agents and steps
- Workflow patterns: route, parallel, loop, repeat
- All process types: sequential, workflow, hierarchical
Usage:
praisonai serve agents.yaml
praisonai serve agents.yaml --port 8005 --host 0.0.0.0
@@ -3090,7 +3095,7 @@ Now, {final_instruction.lower()}:"""
print(" praisonai agents.yaml --serve")
sys.exit(1)
print(f"📄 Loading agents from: {yaml_file}")
print(f"📄 Loading workflow from: {yaml_file}")
# Load YAML file
with open(yaml_file, 'r') as f:
@@ -3124,6 +3129,20 @@ Now, {final_instruction.lower()}:"""
steps = config.get('steps', [])
tasks_list = []
# Detect advanced workflow patterns
has_route = any(isinstance(s, dict) and 'route' in s for s in steps)
has_parallel = any(isinstance(s, dict) and 'parallel' in s for s in steps)
has_loop = any(isinstance(s, dict) and 'loop' in s for s in steps)
has_repeat = any(isinstance(s, dict) and 'repeat' in s for s in steps)
if has_route or has_parallel or has_loop or has_repeat:
patterns = []
if has_route: patterns.append("route")
if has_parallel: patterns.append("parallel")
if has_loop: patterns.append("loop")
if has_repeat: patterns.append("repeat")
print(f"\n🔀 Detected workflow patterns: {', '.join(patterns)}")
if steps:
from praisonaiagents import Task
print(f"\n📋 Loading workflow steps...")
@@ -3132,6 +3151,38 @@ Now, {final_instruction.lower()}:"""
task_name_map = {} # Map step names to Task objects for context/next_tasks
for i, step in enumerate(steps):
if isinstance(step, dict):
# Handle advanced patterns
if 'route' in step:
print(f" ✓ Loaded routing step: {step.get('name', f'route_{i+1}')}")
continue # Route steps are handled by workflow process
if 'parallel' in step:
parallel_tasks = step.get('parallel', [])
print(f" ✓ Loaded parallel step: {len(parallel_tasks)} concurrent tasks")
for j, pt in enumerate(parallel_tasks):
if isinstance(pt, dict):
agent_id = pt.get('agent', '')
action = pt.get('action', pt.get('description', ''))
if agent_id in agents_dict:
task = Task(
name=f"parallel_{i}_{j}",
description=action,
agent=agents_dict[agent_id],
expected_output=pt.get('expected_output', 'Completed task output'),
async_execution=True, # Parallel tasks run async
)
tasks_list.append(task)
task_name_map[f"parallel_{i}_{j}"] = task
continue
if 'loop' in step:
loop_config = step.get('loop', {})
print(f" ✓ Loaded loop step: over '{loop_config.get('over', 'items')}'")
continue # Loop steps are handled by workflow process
if 'repeat' in step:
repeat_config = step.get('repeat', {})
print(f" ✓ Loaded repeat step: until '{repeat_config.get('until', 'done')}'")
continue # Repeat steps are handled by workflow process
# Standard step
agent_id = step.get('agent', '')
action = step.get('action', step.get('description', ''))
task_name = step.get('name', f"step_{i+1}")
@@ -3153,7 +3204,7 @@ Now, {final_instruction.lower()}:"""
# Second pass: set up next_tasks and context relationships
for i, step in enumerate(steps):
if isinstance(step, dict):
if isinstance(step, dict) and 'agent' in step:
task_name = step.get('name', f"step_{i+1}")
if task_name in task_name_map:
task = task_name_map[task_name]
+1 -1
View File
@@ -57,7 +57,7 @@ class CloudDeployer:
file.write("FROM python:3.11-slim\n")
file.write("WORKDIR /app\n")
file.write("COPY . .\n")
file.write("RUN pip install flask praisonai==2.3.34 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.3.35 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+1 -1
View File
@@ -1 +1 @@
__version__ = "2.3.34"
__version__ = "2.3.35"