Compare commits

...
3 Commits
Author SHA1 Message Date
Mervin Praison 4eed985c4d Release v2.3.27 2025-12-17 12:17:02 +00:00
Mervin Praison 0658491072 docs: Update README with workflow features and feature parity
- Add YAML workflow file documentation
- Add workflow auto-generation documentation
- Add complete workflow.yaml reference with all features
- Add feature parity note between agents.yaml and workflow.yaml
- Update workflow CLI options table
2025-12-17 11:52:33 +00:00
Mervin Praison 9f82368b4c feat: Add workflow auto-generation (--auto for workflow.yaml)
- Add WorkflowAutoGenerator class in auto.py with lazy loading
- Support sequential, routing, parallel, loop patterns
- Add 'praisonai workflow auto' CLI command
- Add action_auto to WorkflowHandler
- Add _auto_generate_workflow to main.py
- Uses instructor for structured output generation
- Lazy loading ensures no performance impact when not used

Usage:
  praisonai workflow auto "Research AI trends" --pattern parallel
  praisonai workflow auto "Build a chatbot" --pattern routing
2025-12-17 11:50:02 +00:00
16 changed files with 415 additions and 20 deletions

No files matched your search

+112 -1
View File
@@ -605,6 +605,77 @@ result = manager.execute_yaml(
)
```
### Complete workflow.yaml Reference
```yaml
# workflow.yaml - Full feature reference
name: Complete Workflow
description: Demonstrates all workflow.yaml features
framework: praisonai # praisonai, crewai, autogen
process: workflow # sequential, hierarchical, workflow
workflow:
planning: true
planning_llm: gpt-4o
reasoning: true
verbose: true
memory_config:
provider: chroma
persist: true
variables:
topic: AI trends
items: [ML, NLP, Vision]
agents:
researcher:
name: Researcher
role: Research Analyst
goal: Research topics thoroughly
instructions: "Provide detailed research findings"
backstory: "Expert researcher with 10 years experience" # alias for instructions
llm: gpt-4o-mini
function_calling_llm: gpt-4o # For tool calls
max_rpm: 10 # Rate limiting
max_execution_time: 300 # Timeout in seconds
reflect_llm: gpt-4o # For self-reflection
min_reflect: 1
max_reflect: 3
system_template: "You are a helpful assistant"
tools:
- tavily_search
writer:
name: Writer
role: Content Writer
goal: Write clear content
instructions: "Write engaging content"
steps:
- name: research_step
agent: researcher
action: "Research {{topic}}"
expected_output: "Comprehensive research report"
output_file: "output/research.md"
create_directory: true
- name: writing_step
agent: writer
action: "Write article based on research"
context: # Task dependencies
- research_step
output_json: # Structured output
type: object
properties:
title: { type: string }
content: { type: string }
callbacks:
on_workflow_start: log_start
on_step_complete: log_step
on_workflow_complete: log_complete
```
### 9. Hooks
Configure in `.praison/hooks.json`:
@@ -623,7 +694,14 @@ result = hooks.execute("pre_write_code", {"file": "main.py"})
### 10. Extended agents.yaml with Workflow Patterns
You can now use advanced workflow patterns directly in agents.yaml by setting `process: workflow`:
**Feature Parity:** Both `agents.yaml` and `workflow.yaml` now support the same features:
- All workflow patterns (route, parallel, loop, repeat)
- All agent fields (function_calling_llm, max_rpm, max_execution_time, reflect_llm, templates)
- All step fields (expected_output, context, output_json, create_directory, callback)
- Framework support (praisonai, crewai, autogen)
- Process types (sequential, hierarchical, workflow)
You can use advanced workflow patterns directly in agents.yaml by setting `process: workflow`:
```yaml
# agents.yaml with workflow patterns
@@ -839,10 +917,43 @@ praisonai "GPT-5" --workflow "Research:Search for info,Write:Write blog" --tools
praisonai workflow help
```
#### YAML Workflow Files:
```bash
# Run a YAML workflow file
praisonai workflow run research.yaml
# Run with variables
praisonai workflow run research.yaml --var topic="AI trends"
# Validate a YAML workflow
praisonai workflow validate research.yaml
# Create from template (simple, routing, parallel, loop, evaluator-optimizer)
praisonai workflow template routing --output my_workflow.yaml
```
#### Auto-Generate Workflows:
```bash
# Auto-generate a sequential workflow from topic
praisonai workflow auto "Research AI trends"
# Generate parallel workflow (multiple agents work concurrently)
praisonai workflow auto "Research AI trends" --pattern parallel
# Generate routing workflow (classifier routes to specialists)
praisonai workflow auto "Build a chatbot" --pattern routing
# Specify output file
praisonai workflow auto "Research AI" --pattern sequential --output my_workflow.yaml
```
**Workflow CLI Options:**
| Flag | Description |
|------|-------------|
| `--workflow-var key=value` | Set workflow variable (can be repeated) |
| `--var key=value` | Set variable for YAML workflows |
| `--pattern <pattern>` | Pattern for auto-generation (sequential, parallel, routing, loop) |
| `--output <file>` | Output file for auto-generation |
| `--llm <model>` | LLM model (e.g., openai/gpt-4o-mini) |
| `--tools <tools>` | Tools (comma-separated, e.g., tavily) |
| `--planning` | Enable planning mode |
+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 \
flask \
"praisonai>=2.3.26" \
"praisonai>=2.3.27" \
"praisonai[api]" \
gunicorn \
markdown
+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.26" \
"praisonai>=2.3.27" \
"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.26" \
"praisonai>=2.3.27" \
"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.26" \
"praisonai>=2.3.27" \
"praisonai[ui]" \
"praisonai[crewai]"
@@ -102,7 +102,105 @@ class YAMLWorkflowParser:
Workflow object ready for execution
"""
data = yaml.safe_load(yaml_content)
return self._parse_workflow_data(data)
# Normalize to canonical format (accept both old and new field names)
normalized_data = self._normalize_yaml_config(data)
return self._parse_workflow_data(normalized_data)
def _normalize_yaml_config(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""
Normalize YAML config to canonical format.
Accepts both old (agents.yaml) and new (workflow.yaml) field names.
This implements "Accept liberally, suggest canonically" principle.
Canonical names (preferred):
- agents (not roles)
- instructions (not backstory)
- action (not description)
- steps (not tasks)
- name (not topic)
Args:
data: Raw parsed YAML data
Returns:
Normalized data with canonical field names
"""
if not data:
return data
normalized = data.copy()
# 1. Normalize workflow name: topic -> name
if 'topic' in normalized and 'name' not in normalized:
normalized['name'] = normalized.get('topic', 'Unnamed Workflow')
# 2. Normalize container: roles -> agents
# Note: _convert_roles_to_agents handles backstory -> instructions
if 'roles' in normalized and 'agents' not in normalized:
normalized['agents'] = self._convert_roles_to_agents(normalized['roles'])
# Extract steps from tasks nested in roles if no steps defined
if 'steps' not in normalized:
normalized['steps'] = self._extract_steps_from_roles(normalized['roles'])
# 3. Normalize agent fields: backstory -> instructions (for agents section)
if 'agents' in normalized:
for agent_id, agent_config in normalized['agents'].items():
if isinstance(agent_config, dict):
# backstory -> instructions
if 'backstory' in agent_config and 'instructions' not in agent_config:
agent_config['instructions'] = agent_config['backstory']
# 4. Normalize step fields: description -> action
if 'steps' in normalized:
for step in normalized['steps']:
if isinstance(step, dict):
# description -> action
if 'description' in step and 'action' not in step:
step['action'] = step['description']
# Handle parallel steps
if 'parallel' in step:
for parallel_step in step['parallel']:
if isinstance(parallel_step, dict):
if 'description' in parallel_step and 'action' not in parallel_step:
parallel_step['action'] = parallel_step['description']
return normalized
def _extract_steps_from_roles(self, roles: Dict[str, Dict]) -> List[Dict]:
"""
Extract steps from tasks nested within roles (agents.yaml format).
Args:
roles: The roles section from agents.yaml
Returns:
List of step definitions
"""
steps = []
for role_id, role_config in roles.items():
if 'tasks' in role_config:
for task_id, task_config in role_config['tasks'].items():
step = {
'name': task_id,
'agent': role_id,
}
# description -> action
if 'description' in task_config:
step['action'] = task_config['description']
elif 'action' in task_config:
step['action'] = task_config['action']
# Copy other task fields
for field in ['expected_output', 'context', 'output_file',
'output_json', 'create_directory', 'callback',
'async_execution', 'guardrail', 'max_retries']:
if field in task_config:
step[field] = task_config[field]
steps.append(step)
return steps
def _parse_workflow_data(self, data: Dict[str, Any]) -> Workflow:
"""
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.1.4"
version = "0.1.5"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
requires-python = ">=3.10"
authors = [
+1 -1
View File
@@ -2422,7 +2422,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.1.4"
version = "0.1.5"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
+112 -1
View File
@@ -605,6 +605,77 @@ result = manager.execute_yaml(
)
```
### Complete workflow.yaml Reference
```yaml
# workflow.yaml - Full feature reference
name: Complete Workflow
description: Demonstrates all workflow.yaml features
framework: praisonai # praisonai, crewai, autogen
process: workflow # sequential, hierarchical, workflow
workflow:
planning: true
planning_llm: gpt-4o
reasoning: true
verbose: true
memory_config:
provider: chroma
persist: true
variables:
topic: AI trends
items: [ML, NLP, Vision]
agents:
researcher:
name: Researcher
role: Research Analyst
goal: Research topics thoroughly
instructions: "Provide detailed research findings"
backstory: "Expert researcher with 10 years experience" # alias for instructions
llm: gpt-4o-mini
function_calling_llm: gpt-4o # For tool calls
max_rpm: 10 # Rate limiting
max_execution_time: 300 # Timeout in seconds
reflect_llm: gpt-4o # For self-reflection
min_reflect: 1
max_reflect: 3
system_template: "You are a helpful assistant"
tools:
- tavily_search
writer:
name: Writer
role: Content Writer
goal: Write clear content
instructions: "Write engaging content"
steps:
- name: research_step
agent: researcher
action: "Research {{topic}}"
expected_output: "Comprehensive research report"
output_file: "output/research.md"
create_directory: true
- name: writing_step
agent: writer
action: "Write article based on research"
context: # Task dependencies
- research_step
output_json: # Structured output
type: object
properties:
title: { type: string }
content: { type: string }
callbacks:
on_workflow_start: log_start
on_step_complete: log_step
on_workflow_complete: log_complete
```
### 9. Hooks
Configure in `.praison/hooks.json`:
@@ -623,7 +694,14 @@ result = hooks.execute("pre_write_code", {"file": "main.py"})
### 10. Extended agents.yaml with Workflow Patterns
You can now use advanced workflow patterns directly in agents.yaml by setting `process: workflow`:
**Feature Parity:** Both `agents.yaml` and `workflow.yaml` now support the same features:
- All workflow patterns (route, parallel, loop, repeat)
- All agent fields (function_calling_llm, max_rpm, max_execution_time, reflect_llm, templates)
- All step fields (expected_output, context, output_json, create_directory, callback)
- Framework support (praisonai, crewai, autogen)
- Process types (sequential, hierarchical, workflow)
You can use advanced workflow patterns directly in agents.yaml by setting `process: workflow`:
```yaml
# agents.yaml with workflow patterns
@@ -839,10 +917,43 @@ praisonai "GPT-5" --workflow "Research:Search for info,Write:Write blog" --tools
praisonai workflow help
```
#### YAML Workflow Files:
```bash
# Run a YAML workflow file
praisonai workflow run research.yaml
# Run with variables
praisonai workflow run research.yaml --var topic="AI trends"
# Validate a YAML workflow
praisonai workflow validate research.yaml
# Create from template (simple, routing, parallel, loop, evaluator-optimizer)
praisonai workflow template routing --output my_workflow.yaml
```
#### Auto-Generate Workflows:
```bash
# Auto-generate a sequential workflow from topic
praisonai workflow auto "Research AI trends"
# Generate parallel workflow (multiple agents work concurrently)
praisonai workflow auto "Research AI trends" --pattern parallel
# Generate routing workflow (classifier routes to specialists)
praisonai workflow auto "Build a chatbot" --pattern routing
# Specify output file
praisonai workflow auto "Research AI" --pattern sequential --output my_workflow.yaml
```
**Workflow CLI Options:**
| Flag | Description |
|------|-------------|
| `--workflow-var key=value` | Set workflow variable (can be repeated) |
| `--var key=value` | Set variable for YAML workflows |
| `--pattern <pattern>` | Pattern for auto-generation (sequential, parallel, routing, loop) |
| `--output <file>` | Output file for auto-generation |
| `--llm <model>` | LLM model (e.g., openai/gpt-4o-mini) |
| `--tools <tools>` | Tools (comma-separated, e.g., tavily) |
| `--planning` | Enable planning mode |
+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.26.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.26.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.27.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.27.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
@@ -567,8 +567,8 @@ Example:
return result_path
except ImportError as e:
self.print_status(f"Auto-generation requires instructor: pip install instructor", "error")
except ImportError:
self.print_status("Auto-generation requires instructor: pip install instructor", "error")
return None
except Exception as e:
self.print_status(f"Generation failed: {e}", "error")
+75
View File
@@ -1632,6 +1632,10 @@ class PraisonAI:
if arg == '--output' and i + 1 < len(action_args):
output_file = action_args[i + 1]
self._create_workflow_from_template(template_name, output_file)
elif action == 'auto':
# Auto-generate workflow from topic
self._auto_generate_workflow(action_args)
elif action == 'help' or action == '--help':
print("[bold]Workflow Commands:[/bold]")
@@ -1642,6 +1646,7 @@ class PraisonAI:
print(" praisonai workflow create <name> - Create a new workflow")
print(" praisonai workflow validate <file.yaml> - Validate a YAML workflow")
print(" praisonai workflow template <name> - Create from template")
print(' praisonai workflow auto "topic" - Auto-generate workflow')
print("\n[bold]Templates:[/bold]")
print(" simple, routing, parallel, loop, evaluator-optimizer")
print("\n[bold]Options (uses global flags):[/bold]")
@@ -1839,6 +1844,76 @@ class PraisonAI:
print(f"[green]✓ Created workflow: {output_file}[/green]")
print(f"[cyan]Run with: praisonai workflow run {output_file}[/cyan]")
def _auto_generate_workflow(self, action_args: list):
"""
Auto-generate a workflow from a topic description.
Args:
action_args: ["topic description", --pattern, <pattern>, --output, <file.yaml>]
"""
from rich import print
# Parse arguments
topic = None
pattern = "sequential"
output_file = None
i = 0
while i < len(action_args):
if action_args[i] == "--pattern" and i + 1 < len(action_args):
pattern = action_args[i + 1]
i += 2
elif action_args[i] == "--output" and i + 1 < len(action_args):
output_file = action_args[i + 1]
i += 2
elif not action_args[i].startswith("--") and topic is None:
topic = action_args[i]
i += 1
else:
i += 1
if not topic:
print('[red]Usage: praisonai workflow auto "topic" --pattern <pattern>[/red]')
print("[cyan]Patterns: sequential, routing, parallel[/cyan]")
return
# Validate pattern
valid_patterns = ["sequential", "routing", "parallel", "loop"]
if pattern not in valid_patterns:
print(f"[red]Unknown pattern: {pattern}[/red]")
print(f"[cyan]Valid patterns: {', '.join(valid_patterns)}[/cyan]")
return
# Default output file
if not output_file:
safe_name = "".join(c if c.isalnum() else "_" for c in topic[:30]).lower()
output_file = f"{safe_name}_workflow.yaml"
# Check if file exists
if os.path.exists(output_file):
print(f"[red]ERROR: File already exists: {output_file}[/red]")
return
print(f"[cyan]Generating {pattern} workflow for: {topic}[/cyan]")
try:
from praisonai.auto import WorkflowAutoGenerator
generator = WorkflowAutoGenerator(
topic=topic,
workflow_file=output_file
)
result_path = generator.generate(pattern=pattern)
print(f"[green]✓ Created workflow: {result_path}[/green]")
print(f"[cyan]Run with: praisonai workflow run {output_file}[/cyan]")
except ImportError:
print("[red]Auto-generation requires instructor: pip install instructor[/red]")
except Exception as e:
print(f"[red]Generation failed: {e}[/red]")
def handle_hooks_command(self, action: str):
"""
Handle hooks subcommand actions.
+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.26 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.3.27 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.26"
__version__ = "2.3.27"
+1 -1
View File
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.1.4",
"praisonaiagents>=0.1.5",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
+4 -4
View File
@@ -4197,7 +4197,7 @@ requires-dist = [
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.22" },
{ name = "praisonai-tools", marker = "extra == 'autogen-v4'", specifier = ">=0.0.22" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.22" },
{ name = "praisonaiagents", specifier = ">=0.1.4" },
{ name = "praisonaiagents", specifier = ">=0.1.5" },
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = "==0.2.29" },
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
@@ -4252,7 +4252,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.1.4"
version = "0.1.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -4261,9 +4261,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ab/9d/d286e0ba5421cb8a37ea86f4714a7fbcb39fe1f38e9a202cf0cf6381ae8c/praisonaiagents-0.1.4.tar.gz", hash = "sha256:d00a326ac65701bcc66c44aba7d1616ef1317a2491034a242ad4290f0269e190", size = 560571, upload-time = "2025-12-17T11:43:41.829Z" }
sdist = { url = "https://files.pythonhosted.org/packages/b5/ac/d9ac00fb329de508001dea2d386f82a82432a7c5faef2990977e9e26a02f/praisonaiagents-0.1.5.tar.gz", hash = "sha256:87546f19686d9b0ddc163fb78d2567b6758e44e75d3e36fd5de022f8a57a45de", size = 560563, upload-time = "2025-12-17T12:04:27.818Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f3/90/b6429a58f75aeec4da0034d7594863b3fd6e4bf916dbcbeb53a8597f0f4a/praisonaiagents-0.1.4-py3-none-any.whl", hash = "sha256:c7ad9b64e3d3a24b9560d695bc7447f286928e52f0979e84d02484662cb8a49d", size = 524190, upload-time = "2025-12-17T11:43:40.119Z" },
{ url = "https://files.pythonhosted.org/packages/60/e7/f06997b7843b17de3f30f699299fe661218e0291e006f386ae280c53c80d/praisonaiagents-0.1.5-py3-none-any.whl", hash = "sha256:4733f5e7ed131f7acba9315f64e80ed137df34496a0bf0892dfd3ad2aea2e212", size = 524190, upload-time = "2025-12-17T12:04:26.368Z" },
]
[[package]]