From c41b2e5d300e72eae3d5407984a2e89fcf0ec600 Mon Sep 17 00:00:00 2001 From: vizsatiz Date: Sat, 23 Aug 2025 11:39:47 +0530 Subject: [PATCH 1/8] Updating 1.0.0 version --- flo_ai/pyproject.toml | 2 +- flo_ai/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flo_ai/pyproject.toml b/flo_ai/pyproject.toml index c7e758a8..18f45454 100644 --- a/flo_ai/pyproject.toml +++ b/flo_ai/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "flo_ai" -version = "1.0.0-dev5" +version = "1.0.0" description = "A easy way to create structured AI agents" authors = ["rootflo <*@rootflo.ai>"] license = "MIT" diff --git a/flo_ai/setup.py b/flo_ai/setup.py index c2d924f9..0e7e702e 100644 --- a/flo_ai/setup.py +++ b/flo_ai/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='flo-ai', - version='1.0.0-dev5', + version='1.0.0', author='Rootflo', description='Create composable AI agents', long_description=long_description, From b14be393ae7fd0b7e912e2451d448da4d80d2854 Mon Sep 17 00:00:00 2001 From: Vishnu Satis Date: Sat, 23 Aug 2025 23:01:56 +0530 Subject: [PATCH 2/8] Patterns: Reflection & Plan-Execute Pattern (#120) * Adding support for Reflection Pattern * Plan&Execute router --- README.md | 558 ++++++++++++++++++ flo_ai/examples/concept_demo.py | 284 +++++++++ flo_ai/examples/fixed_plan_execute_demo.py | 401 +++++++++++++ flo_ai/examples/flow_router_example.py | 454 ++++++++++++++ flo_ai/examples/live_plan_execute_demo.py | 307 ++++++++++ .../examples/plan_execute_router_example.py | 501 ++++++++++++++++ flo_ai/examples/reflection_router_example.py | 454 ++++++++++++++ flo_ai/examples/simple_flow_router_demo.py | 181 ++++++ flo_ai/examples/simple_plan_execute_demo.py | 418 +++++++++++++ .../examples/simple_reflection_router_demo.py | 188 ++++++ flo_ai/examples/simple_working_demo.py | 335 +++++++++++ flo_ai/flo_ai/arium/base.py | 34 +- flo_ai/flo_ai/arium/builder.py | 52 +- flo_ai/flo_ai/arium/llm_router.py | 511 +++++++++++++++- flo_ai/flo_ai/arium/memory.py | 159 ++++- 15 files changed, 4825 insertions(+), 12 deletions(-) create mode 100644 flo_ai/examples/concept_demo.py create mode 100644 flo_ai/examples/fixed_plan_execute_demo.py create mode 100644 flo_ai/examples/flow_router_example.py create mode 100644 flo_ai/examples/live_plan_execute_demo.py create mode 100644 flo_ai/examples/plan_execute_router_example.py create mode 100644 flo_ai/examples/reflection_router_example.py create mode 100644 flo_ai/examples/simple_flow_router_demo.py create mode 100644 flo_ai/examples/simple_plan_execute_demo.py create mode 100644 flo_ai/examples/simple_reflection_router_demo.py create mode 100644 flo_ai/examples/simple_working_demo.py diff --git a/README.md b/README.md index b4995f86..542365e1 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,8 @@ Flo AI is a Python framework that makes building production-ready AI agents and - [Builder Pattern Benefits](#builder-pattern-benefits) - [πŸ“„ YAML-Based Arium Workflows](#-yaml-based-arium-workflows) - [🧠 LLM-Powered Routers in YAML (NEW!)](#-llm-powered-routers-in-yaml-new) + - [πŸ”„ ReflectionRouter: Structured Reflection Workflows (NEW!)](#-reflectionrouter-structured-reflection-workflows-new) + - [πŸ”„ PlanExecuteRouter: Cursor-Style Plan-and-Execute Workflows (NEW!)](#-planexecuterouter-cursor-style-plan-and-execute-workflows-new) - [πŸ“– Documentation](#-documentation) - [🌟 Why Flo AI?](#-why-flo-ai) - [🎯 Use Cases](#-use-cases) @@ -1429,6 +1431,8 @@ arium: 1. **Smart Router** (`type: smart`): General-purpose routing based on content analysis 2. **Task Classifier** (`type: task_classifier`): Routes based on keywords and examples 3. **Conversation Analysis** (`type: conversation_analysis`): Context-aware routing +4. **Reflection Router** (`type: reflection`): Structured Aβ†’Bβ†’Aβ†’C patterns for reflection workflows +5. **PlanExecute Router** (`type: plan_execute`): Cursor-style plan-and-execute workflows with step tracking **✨ Key Benefits:** - 🚫 **No Code Required**: Define routing logic purely in YAML @@ -1450,6 +1454,560 @@ async def run_intelligent_workflow(): return result ``` +##### πŸ”„ ReflectionRouter: Structured Reflection Workflows (NEW!) + +The **ReflectionRouter** is designed specifically for reflection-based workflows that follow Aβ†’Bβ†’Aβ†’C patterns, commonly used for mainβ†’criticβ†’mainβ†’final agent sequences. This pattern is perfect for iterative improvement workflows where a critic agent provides feedback before final processing. + +**πŸ“‹ Key Features:** +- 🎯 **Pattern Tracking**: Automatically tracks progress through defined reflection sequences +- πŸ”„ **Self-Reference Support**: Allows routing back to the same agent (Aβ†’Bβ†’A patterns) +- πŸ“Š **Visual Progress**: Shows current position with β—‹ pending, βœ“ completed indicators +- πŸ›‘οΈ **Loop Prevention**: Built-in safety mechanisms to prevent infinite loops +- πŸŽ›οΈ **Flexible Patterns**: Supports both 2-agent (Aβ†’Bβ†’A) and 3-agent (Aβ†’Bβ†’Aβ†’C) flows + +**🎯 Supported Patterns:** + +1. **A β†’ B β†’ A** (2 agents): Main β†’ Critic β†’ Main β†’ End +2. **A β†’ B β†’ A β†’ C** (3 agents): Main β†’ Critic β†’ Main β†’ Final + +```yaml +# Simple A β†’ B β†’ A reflection pattern +metadata: + name: "content-reflection-workflow" + version: "1.0.0" + description: "Content creation with critic feedback loop" + +arium: + agents: + - name: "writer" + role: "Content Writer" + job: "Create and improve content based on feedback from critics." + model: + provider: "openai" + name: "gpt-4o-mini" + settings: + temperature: 0.7 + + - name: "critic" + role: "Content Critic" + job: "Review content and provide constructive feedback for improvement." + model: + provider: "openai" + name: "gpt-4o-mini" + settings: + temperature: 0.3 + + # ✨ ReflectionRouter definition + routers: + - name: "reflection_router" + type: "reflection" # Specialized for reflection patterns + flow_pattern: [writer, critic, writer] # A β†’ B β†’ A pattern + model: + provider: "openai" + name: "gpt-4o-mini" + settings: + temperature: 0.2 + allow_early_exit: false # Strict adherence to pattern + + workflow: + start: "writer" + edges: + - from: "writer" + to: [critic, writer] # Can go to critic or self-reference + router: "reflection_router" + - from: "critic" + to: [writer] # Always returns to writer + router: "reflection_router" + end: [writer] # Writer produces final output +``` + +```yaml +# Advanced A β†’ B β†’ A β†’ C reflection pattern +metadata: + name: "advanced-reflection-workflow" + version: "1.0.0" + description: "Full reflection cycle with dedicated final agent" + +arium: + agents: + - name: "researcher" + role: "Research Agent" + job: "Conduct research and gather information on topics." + model: + provider: "openai" + name: "gpt-4o-mini" + + - name: "reviewer" + role: "Research Reviewer" + job: "Review research quality and suggest improvements." + model: + provider: "anthropic" + name: "claude-3-5-sonnet-20240620" + + - name: "synthesizer" + role: "Information Synthesizer" + job: "Create final synthesis and conclusions from research." + model: + provider: "openai" + name: "gpt-4o" + + routers: + - name: "research_reflection_router" + type: "reflection" + flow_pattern: [researcher, reviewer, researcher, synthesizer] # A β†’ B β†’ A β†’ C + settings: + allow_early_exit: true # Allow smart early completion + + workflow: + start: "researcher" + edges: + - from: "researcher" + to: [reviewer, researcher, synthesizer] # All possible destinations + router: "research_reflection_router" + - from: "reviewer" + to: [researcher, reviewer, synthesizer] + router: "research_reflection_router" + - from: "synthesizer" + to: [end] + end: [synthesizer] +``` + +**πŸ”§ ReflectionRouter Configuration Options:** + +```yaml +routers: + - name: "my_reflection_router" + type: "reflection" + flow_pattern: [main_agent, critic, main_agent, final_agent] # Define your pattern + model: # Optional: LLM for routing decisions + provider: "openai" + name: "gpt-4o-mini" + settings: # Optional settings + temperature: 0.2 # Router temperature (lower = more deterministic) + allow_early_exit: false # Allow early completion if LLM determines pattern is done + fallback_strategy: "first" # first, last, random - fallback when LLM fails +``` + +**πŸ—οΈ Programmatic Usage:** + +```python +import asyncio +from flo_ai.arium import AriumBuilder +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.llm_router import create_main_critic_reflection_router + +async def reflection_workflow_example(): + llm = OpenAI(model='gpt-4o-mini', api_key='your-api-key') + + # Create agents + main_agent = Agent( + name='main_agent', + system_prompt='Create solutions and improve them based on feedback.', + llm=llm + ) + + critic = Agent( + name='critic', + system_prompt='Provide constructive feedback for improvement.', + llm=llm + ) + + final_agent = Agent( + name='final_agent', + system_prompt='Polish and finalize the work.', + llm=llm + ) + + # Create reflection router - A β†’ B β†’ A β†’ C pattern + reflection_router = create_main_critic_reflection_router( + main_agent='main_agent', + critic_agent='critic', + final_agent='final_agent', + allow_early_exit=False, # Strict pattern adherence + llm=llm + ) + + # Build workflow + result = await ( + AriumBuilder() + .add_agents([main_agent, critic, final_agent]) + .start_with(main_agent) + .add_edge(main_agent, [critic, final_agent], reflection_router) + .add_edge(critic, [main_agent, final_agent], reflection_router) + .end_with(final_agent) + .build_and_run(["Create a comprehensive project proposal"]) + ) + + return result + +# Alternative: Direct factory usage +from flo_ai.arium.llm_router import create_llm_router + +reflection_router = create_llm_router( + 'reflection', + flow_pattern=['writer', 'editor', 'writer'], # A β†’ B β†’ A + allow_early_exit=False, + llm=llm +) +``` + +**πŸ’‘ ReflectionRouter Intelligence:** + +The ReflectionRouter automatically: +- **Tracks Progress**: Knows which step in the pattern should execute next +- **Prevents Loops**: Uses execution context to avoid infinite cycles +- **Provides Guidance**: Shows LLM the suggested next step and current progress +- **Handles Self-Reference**: Properly validates flows that return to the same agent +- **Visual Feedback**: Displays pattern progress: `β—‹ writer β†’ βœ“ critic β†’ β—‹ writer` + +**🎯 Perfect Use Cases:** +- πŸ“ **Content Creation**: Writer β†’ Editor β†’ Writer β†’ Publisher +- πŸ”¬ **Research Workflows**: Researcher β†’ Reviewer β†’ Researcher β†’ Synthesizer +- πŸ’Ό **Business Analysis**: Analyst β†’ Critic β†’ Analyst β†’ Decision Maker +- 🎨 **Creative Processes**: Creator β†’ Critic β†’ Creator β†’ Finalizer +- πŸ§ͺ **Iterative Refinement**: Any process requiring feedback and improvement cycles + +**⚑ Quick Start Example:** + +```python +# Minimal A β†’ B β†’ A pattern +yaml_config = """ +arium: + agents: + - name: main_agent + job: "Main work agent" + model: {provider: openai, name: gpt-4o-mini} + - name: critic + job: "Feedback agent" + model: {provider: openai, name: gpt-4o-mini} + + routers: + - name: reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent] + + workflow: + start: main_agent + edges: + - from: main_agent + to: [critic, main_agent] + router: reflection_router + - from: critic + to: [main_agent] + router: reflection_router + end: [main_agent] +""" + +result = await AriumBuilder().from_yaml(yaml_str=yaml_config).build_and_run(["Your task"]) +``` + +The ReflectionRouter makes implementing sophisticated feedback loops and iterative improvement workflows incredibly simple, whether you need a 2-agent or 3-agent pattern! πŸš€ + +##### πŸ”„ PlanExecuteRouter: Cursor-Style Plan-and-Execute Workflows (NEW!) + +The **PlanExecuteRouter** implements sophisticated plan-and-execute patterns similar to how Cursor works. It automatically breaks down complex tasks into detailed execution plans and coordinates step-by-step execution with intelligent progress tracking. + +**πŸ“‹ Key Features:** +- 🎯 **Automatic Task Breakdown**: Creates detailed execution plans from high-level tasks +- πŸ“Š **Step Tracking**: Real-time progress monitoring with visual indicators (β—‹ ⏳ βœ… ❌) +- πŸ”„ **Phase Coordination**: Intelligent routing between planning, execution, and review phases +- πŸ›‘οΈ **Dependency Management**: Handles step dependencies and execution order automatically +- πŸ’Ύ **Plan Persistence**: Uses PlanAwareMemory for stateful plan storage and updates +- πŸ”§ **Error Recovery**: Built-in retry logic for failed steps + +**🎯 Perfect for Cursor-Style Workflows:** +- πŸ’» **Software Development**: Requirements β†’ Design β†’ Implementation β†’ Testing β†’ Review +- πŸ“ **Content Creation**: Planning β†’ Writing β†’ Editing β†’ Review β†’ Publishing +- πŸ”¬ **Research Projects**: Plan β†’ Investigate β†’ Analyze β†’ Synthesize β†’ Report +- πŸ“Š **Business Processes**: Any multi-step workflow with dependencies + +**πŸ“„ YAML Configuration:** + +```yaml +# Complete Plan-Execute Workflow +metadata: + name: "development-plan-execute" + version: "1.0.0" + description: "Cursor-style development workflow" + +arium: + agents: + - name: planner + role: Project Planner + job: > + Break down complex development tasks into detailed, sequential execution plans. + Create clear steps with dependencies and agent assignments. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + - name: developer + role: Software Developer + job: > + Implement features step by step according to execution plans. + Provide detailed implementation and update step status. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.5 + + - name: tester + role: QA Engineer + job: > + Test implementations thoroughly and validate functionality. + Create comprehensive test scenarios and report results. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + + - name: reviewer + role: Senior Reviewer + job: > + Provide final quality assessment and approval. + Review completed work for best practices and requirements. + model: + provider: openai + name: gpt-4o-mini + + # PlanExecuteRouter configuration + routers: + - name: dev_plan_router + type: plan_execute # Router type for plan-execute workflows + agents: # Available agents and their capabilities + planner: "Creates detailed execution plans by breaking down tasks" + developer: "Implements features and code according to plan specifications" + tester: "Tests implementations and validates functionality" + reviewer: "Reviews and approves completed work" + model: # Optional: LLM for routing decisions + provider: openai + name: gpt-4o-mini + settings: # Optional configuration + temperature: 0.2 # Router decision temperature + planner_agent: planner # Agent responsible for creating plans + executor_agent: developer # Default agent for executing steps + reviewer_agent: reviewer # Optional agent for final review + max_retries: 3 # Maximum retries for failed steps + + workflow: + start: planner + edges: + # All agents can route to all others based on plan state + - from: planner + to: [developer, tester, reviewer, planner] + router: dev_plan_router + - from: developer + to: [developer, tester, reviewer, planner] + router: dev_plan_router + - from: tester + to: [developer, tester, reviewer, planner] + router: dev_plan_router + - from: reviewer + to: [end] + end: [reviewer] +``` + +**πŸ—οΈ Programmatic Usage:** + +```python +import asyncio +from flo_ai.arium import AriumBuilder +from flo_ai.arium.memory import PlanAwareMemory +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.llm_router import create_plan_execute_router + +async def cursor_style_workflow(): + llm = OpenAI(model='gpt-4o-mini', api_key='your-api-key') + + # Create specialized agents + planner = Agent( + name='planner', + system_prompt='Create detailed execution plans by breaking down tasks into sequential steps.', + llm=llm + ) + + developer = Agent( + name='developer', + system_prompt='Implement features step by step according to execution plans.', + llm=llm + ) + + tester = Agent( + name='tester', + system_prompt='Test implementations and validate functionality thoroughly.', + llm=llm + ) + + reviewer = Agent( + name='reviewer', + system_prompt='Review completed work and provide final approval.', + llm=llm + ) + + # Create plan-execute router + plan_router = create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer', + additional_agents={'tester': 'Tests implementations and validates quality'}, + llm=llm + ) + + # Use PlanAwareMemory for plan state persistence + memory = PlanAwareMemory() + + # Build and run workflow + result = await ( + AriumBuilder() + .with_memory(memory) + .add_agents([planner, developer, tester, reviewer]) + .start_with(planner) + .add_edge(planner, [developer, tester, reviewer, planner], plan_router) + .add_edge(developer, [developer, tester, reviewer, planner], plan_router) + .add_edge(tester, [developer, tester, reviewer, planner], plan_router) + .add_edge(reviewer, [developer, tester, reviewer, planner], plan_router) + .end_with(reviewer) + .build_and_run(["Create a REST API for user authentication with JWT tokens"]) + ) + + return result + +# Alternative: Factory function +from flo_ai.arium.llm_router import create_plan_execute_router + +plan_router = create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer', + llm=llm +) +``` + +**πŸ’‘ How PlanExecuteRouter Works:** + +The router intelligently coordinates workflow phases: + +1. **Planning Phase**: + - Detects when no execution plan exists + - Routes to planner agent to create detailed plan + - Plan stored as ExecutionPlan object in PlanAwareMemory + +2. **Execution Phase**: + - Analyzes plan state and step dependencies + - Routes to appropriate agents for next ready steps + - Updates step status (pending β†’ in-progress β†’ completed) + - Handles parallel execution of independent steps + +3. **Review Phase**: + - Detects when all steps are completed + - Routes to reviewer agent for final validation + - Manages error recovery for failed steps + +**πŸ“Š Plan Progress Visualization:** + +``` +πŸ“‹ EXECUTION PLAN: User Authentication API +πŸ“Š CURRENT PROGRESS: +βœ… design_schema: Design user database schema β†’ developer +βœ… implement_registration: Create registration endpoint β†’ developer +⏳ implement_login: Add login with JWT β†’ developer (depends: design_schema, implement_registration) +β—‹ add_middleware: Authentication middleware β†’ developer (depends: implement_login) +β—‹ write_tests: Comprehensive testing β†’ tester (depends: add_middleware) +β—‹ final_review: Security and code review β†’ reviewer (depends: write_tests) + +🎯 NEXT ACTION: Execute step 'implement_login' +🎯 SUGGESTED AGENT: developer +``` + +**πŸ”§ Advanced Configuration Options:** + +```yaml +routers: + - name: advanced_plan_router + type: plan_execute + agents: + planner: "Creates execution plans" + frontend_dev: "Frontend implementation" + backend_dev: "Backend implementation" + devops: "Deployment and infrastructure" + qa_tester: "Quality assurance testing" + security_reviewer: "Security review" + product_owner: "Product validation" + model: + provider: openai + name: gpt-4o + settings: + temperature: 0.1 # Lower for more deterministic routing + planner_agent: planner # Plan creation agent + executor_agent: backend_dev # Default execution agent + reviewer_agent: product_owner # Final review agent + max_retries: 5 # Retry attempts for failed steps + allow_parallel_execution: true # Enable parallel step execution + plan_validation: strict # Validate plan completeness +``` + +**⚑ Quick Start Example:** + +```python +# Minimal plan-execute workflow +yaml_config = """ +arium: + agents: + - name: planner + job: "Create execution plans" + model: {provider: openai, name: gpt-4o-mini} + - name: executor + job: "Execute plan steps" + model: {provider: openai, name: gpt-4o-mini} + - name: reviewer + job: "Review final results" + model: {provider: openai, name: gpt-4o-mini} + + routers: + - name: simple_plan_router + type: plan_execute + agents: + planner: "Creates plans" + executor: "Executes steps" + reviewer: "Reviews results" + settings: + planner_agent: planner + executor_agent: executor + reviewer_agent: reviewer + + workflow: + start: planner + edges: + - from: planner + to: [executor, reviewer, planner] + router: simple_plan_router + - from: executor + to: [executor, reviewer, planner] + router: simple_plan_router + - from: reviewer + to: [end] + end: [reviewer] +""" + +result = await AriumBuilder().from_yaml(yaml_str=yaml_config).build_and_run(["Your complex task"]) +``` + +**🎯 Use Cases and Examples:** + +- πŸ“± **App Development**: "Build a todo app with React and Node.js" +- πŸ›’ **E-commerce**: "Create a shopping cart system with payment processing" +- πŸ“Š **Data Pipeline**: "Build ETL pipeline for customer analytics" +- πŸ” **Security**: "Implement OAuth2 authentication system" +- πŸ“ˆ **Analytics**: "Create real-time dashboard with user metrics" + +The PlanExecuteRouter brings Cursor-style intelligent task automation to Flo AI, making it incredibly easy to build sophisticated multi-step workflows that adapt and execute complex tasks automatically! πŸš€ + #### YAML Workflow with Variables ```yaml diff --git a/flo_ai/examples/concept_demo.py b/flo_ai/examples/concept_demo.py new file mode 100644 index 00000000..ab573783 --- /dev/null +++ b/flo_ai/examples/concept_demo.py @@ -0,0 +1,284 @@ +""" +PlanExecuteRouter Concept Demo + +This demonstrates the plan-execute concept without requiring API calls. +Shows the architecture and explains how to fix the planner loop issue. +""" + +import asyncio +from flo_ai.arium.memory import PlanAwareMemory, ExecutionPlan, PlanStep, StepStatus +import uuid + + +def demonstrate_plan_aware_memory(): + """Show how PlanAwareMemory works with ExecutionPlan objects""" + print('πŸ“‹ PlanAwareMemory Concept Demo') + print('=' * 35) + + # Create memory + memory = PlanAwareMemory() + + # Create a sample execution plan + plan = ExecutionPlan( + id=str(uuid.uuid4()), + title='Build User Authentication API', + description='Create complete user auth system with registration and login', + steps=[ + PlanStep( + id='design_schema', + description='Design user database schema', + agent='developer', + status=StepStatus.PENDING, + ), + PlanStep( + id='implement_registration', + description='Implement user registration endpoint', + agent='developer', + dependencies=['design_schema'], + status=StepStatus.PENDING, + ), + PlanStep( + id='implement_login', + description='Implement user login with JWT tokens', + agent='developer', + dependencies=['design_schema', 'implement_registration'], + status=StepStatus.PENDING, + ), + PlanStep( + id='test_endpoints', + description='Test all authentication endpoints', + agent='tester', + dependencies=['implement_login'], + status=StepStatus.PENDING, + ), + PlanStep( + id='security_review', + description='Review security implementation', + agent='reviewer', + dependencies=['test_endpoints'], + status=StepStatus.PENDING, + ), + ], + ) + + # Store plan in memory + memory.add_plan(plan) + print(f'βœ… Plan stored: {plan.title}') + print(f'πŸ“Š Total steps: {len(plan.steps)}') + + # Show initial state + def show_plan_status(): + current = memory.get_current_plan() + print(f'\nπŸ“‹ Plan Status: {current.title}') + for step in current.steps: + status_icon = { + StepStatus.PENDING: 'β—‹', + StepStatus.IN_PROGRESS: '⏳', + StepStatus.COMPLETED: 'βœ…', + StepStatus.FAILED: '❌', + }.get(step.status, 'β—‹') + deps = ( + f" (depends: {', '.join(step.dependencies)})" + if step.dependencies + else '' + ) + print(f' {status_icon} {step.id}: {step.description} β†’ {step.agent}{deps}') + + show_plan_status() + + # Simulate step execution + print('\nπŸ”„ Simulating step-by-step execution...') + + current_plan = memory.get_current_plan() + + # Execute step 1 + next_steps = current_plan.get_next_steps() + print(f'\n🎯 Next steps ready: {len(next_steps)}') + step1 = next_steps[0] + print(f'⏳ Executing: {step1.description}') + step1.status = StepStatus.COMPLETED + step1.result = 'User table created with id, email, password_hash fields' + memory.update_plan(current_plan) + + # Execute step 2 + next_steps = current_plan.get_next_steps() + print(f'\n🎯 Next steps ready: {len(next_steps)}') + step2 = next_steps[0] + print(f'⏳ Executing: {step2.description}') + step2.status = StepStatus.COMPLETED + step2.result = 'POST /register endpoint with validation implemented' + memory.update_plan(current_plan) + + show_plan_status() + + print(f'\nπŸ“ˆ Plan completion status: {current_plan.is_completed()}') + print(f'πŸ“Š Remaining steps: {len(current_plan.get_next_steps())}') + + +def explain_planner_loop_issue(): + """Explain why the planner got stuck in a loop and how to fix it""" + print('\n\nπŸ”„ Understanding the Planner Loop Issue') + print('=' * 45) + + explanation = """ +❌ THE PROBLEM: +In the original demo, the planner kept getting called in an infinite loop because: + +1. Router asks: "Is there a plan in memory?" +2. Memory says: "No ExecutionPlan objects found" +3. Router decides: "Route to planner to create plan" +4. Planner generates plan TEXT but doesn't store ExecutionPlan OBJECTS +5. Router asks again: "Is there a plan in memory?" +6. Memory still says: "No ExecutionPlan objects found" +7. INFINITE LOOP! πŸ”„ + +βœ… THE SOLUTION: +We need to bridge the gap between plan TEXT and plan OBJECTS: + +APPROACH 1: Specialized PlannerAgent +β€’ Custom agent that parses plan text and stores ExecutionPlan objects +β€’ Router can detect when ExecutionPlan exists in memory +β€’ Automatically switches from planning to execution phase + +APPROACH 2: Content-Based Routing +β€’ Router analyzes message content instead of relying on ExecutionPlan objects +β€’ If message contains "PLAN:", switch to execution mode +β€’ Simpler but less sophisticated + +APPROACH 3: State Management +β€’ Explicitly track workflow state (planning/executing/reviewing) +β€’ Router uses state instead of trying to detect plan completion +β€’ Most reliable but requires more setup +""" + + print(explanation) + + +def show_router_intelligence(): + """Show how the PlanExecuteRouter makes intelligent decisions""" + print('\n\n🧠 PlanExecuteRouter Intelligence') + print('=' * 35) + + intelligence_demo = """ +The PlanExecuteRouter is designed to coordinate complex workflows by: + +🎯 PHASE DETECTION: +β€’ Planning Phase: No plan exists β†’ route to planner +β€’ Execution Phase: Plan exists with pending steps β†’ route to executor +β€’ Review Phase: All steps complete β†’ route to reviewer +β€’ Error Recovery: Failed steps exist β†’ route for retry + +πŸ“Š STEP MANAGEMENT: +β€’ Analyzes step dependencies automatically +β€’ Only executes steps when dependencies are met +β€’ Tracks progress with visual indicators (β—‹ ⏳ βœ… ❌) +β€’ Handles parallel execution of independent steps + +πŸ”„ INTELLIGENT ROUTING: +β€’ Context-aware prompts with plan progress +β€’ Suggests next agent based on plan state +β€’ Prevents infinite loops with completion detection +β€’ Adapts to different workflow patterns + +πŸ’‘ EXAMPLE ROUTING DECISIONS: + +Scenario 1: No plan exists +β†’ Router: "Route to planner to create execution plan" + +Scenario 2: Plan exists, step_1 ready +β†’ Router: "Route to developer to execute step_1" + +Scenario 3: Development complete, testing needed +β†’ Router: "Route to tester to validate implementation" + +Scenario 4: All steps complete +β†’ Router: "Route to reviewer for final approval" + +Scenario 5: Step failed +β†’ Router: "Route to developer to retry failed step" +""" + + print(intelligence_demo) + + +def show_working_implementation(): + """Show the key components of a working implementation""" + print('\n\nπŸ—οΈ Working Implementation Components') + print('=' * 40) + + implementation = """ +For a working PlanExecuteRouter implementation, you need: + +1. πŸ“‹ PLAN STORAGE: + ```python + memory = PlanAwareMemory() # Stores ExecutionPlan objects + plan = ExecutionPlan(title="...", steps=[...]) + memory.add_plan(plan) + ``` + +2. πŸ€– SPECIALIZED AGENTS: + ```python + class PlannerAgent(Agent): + def run(self, input_data): + plan_text = await super().run(input_data) + execution_plan = self.parse_plan(plan_text) + self.memory.add_plan(execution_plan) # KEY! + return plan_text + ``` + +3. 🎯 SMART ROUTING: + ```python + router = create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer' + ) + ``` + +4. πŸ”„ WORKFLOW COORDINATION: + ```python + arium = AriumBuilder() + .with_memory(memory) # PlanAwareMemory + .add_agents([planner, developer, tester, reviewer]) + .add_edge(planner, [...], router) + .build() + ``` + +🎯 CRITICAL SUCCESS FACTORS: +β€’ PlannerAgent MUST store ExecutionPlan objects +β€’ Use PlanAwareMemory for plan state persistence +β€’ Router needs to detect plan existence reliably +β€’ Agents should update step status during execution +""" + + print(implementation) + + +async def main(): + """Main concept demo""" + print('🎯 PlanExecuteRouter Concept Demo') + print('Understanding the architecture and fixing the planner loop\n') + + # Demonstrate core concepts + demonstrate_plan_aware_memory() + explain_planner_loop_issue() + show_router_intelligence() + show_working_implementation() + + print('\n\nπŸŽ‰ Concept Demo Complete!') + print('=' * 30) + print('Key Takeaways:') + print('βœ… PlanExecuteRouter enables Cursor-style plan-and-execute workflows') + print('βœ… Planner loop occurs when plan TEXT β‰  plan OBJECTS in memory') + print('βœ… Solution: Bridge the gap with specialized agents or content parsing') + print('βœ… Working implementation requires PlanAwareMemory + ExecutionPlan objects') + + print('\nπŸš€ Next Steps:') + print('β€’ Try fixed_plan_execute_demo.py for working implementation') + print('β€’ Use PlannerAgent that stores ExecutionPlan objects') + print('β€’ Implement step status tracking for real progress monitoring') + print('β€’ Customize agents for your specific workflow needs') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/fixed_plan_execute_demo.py b/flo_ai/examples/fixed_plan_execute_demo.py new file mode 100644 index 00000000..a5976c8b --- /dev/null +++ b/flo_ai/examples/fixed_plan_execute_demo.py @@ -0,0 +1,401 @@ +""" +Fixed PlanExecuteRouter Demo - Resolves the planner loop issue + +The previous demo had an issue where the planner kept looping because the plan +wasn't being properly stored in PlanAwareMemory. This version fixes that by: + +1. Creating a special PlannerAgent that stores ExecutionPlan objects +2. Ensuring the router can detect when plans are created +3. Proper integration between plan creation and execution phases +""" + +import asyncio +import os +import uuid +import re +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.memory import PlanAwareMemory, ExecutionPlan, PlanStep, StepStatus +from flo_ai.arium.llm_router import create_plan_execute_router +from flo_ai.arium import AriumBuilder + + +class PlannerAgent(Agent): + """Special agent that creates ExecutionPlan objects and stores them in memory""" + + def __init__(self, memory: PlanAwareMemory, **kwargs): + super().__init__(**kwargs) + self.memory = memory + + async def run(self, input_data, **kwargs): + """Override run to create and store ExecutionPlan after generating plan text""" + + # First, generate the plan text using the normal agent behavior + plan_text = await super().run(input_data, **kwargs) + + # Parse the plan text and create ExecutionPlan object + execution_plan = self._parse_plan_text(plan_text) + + # Store the plan in memory + if execution_plan: + self.memory.add_plan(execution_plan) + print(f'βœ… Plan stored in memory: {execution_plan.title}') + print(f'πŸ“Š Steps: {len(execution_plan.steps)}') + + # Show the plan + for i, step in enumerate(execution_plan.steps, 1): + deps = ( + f" (depends: {', '.join(step.dependencies)})" + if step.dependencies + else '' + ) + print(f' {i}. {step.id}: {step.description} β†’ {step.agent}{deps}') + + return plan_text + + def _parse_plan_text(self, plan_text: str) -> ExecutionPlan: + """Parse LLM-generated plan text into ExecutionPlan object""" + + # Extract title + title_match = re.search(r'EXECUTION PLAN:\s*(.+)', plan_text) + title = title_match.group(1).strip() if title_match else 'Generated Plan' + + # Extract description + desc_match = re.search(r'DESCRIPTION:\s*(.+)', plan_text) + description = desc_match.group(1).strip() if desc_match else 'Execution plan' + + # Extract steps using regex + steps = [] + step_pattern = ( + r'(\d+)\.\s*(\w+):\s*(.+?)\s*β†’\s*(\w+)(?:\s*\(depends on:\s*([^)]+)\))?' + ) + + for match in re.finditer(step_pattern, plan_text, re.MULTILINE): + step_num, step_id, step_desc, agent, deps_str = match.groups() + + dependencies = [] + if deps_str: + dependencies = [dep.strip() for dep in deps_str.split(',')] + + step = PlanStep( + id=step_id, + description=step_desc.strip(), + agent=agent, + dependencies=dependencies, + status=StepStatus.PENDING, + ) + steps.append(step) + + return ExecutionPlan( + id=str(uuid.uuid4()), + title=title, + description=description, + steps=steps, + created_by=self.name, + ) + + +class ExecutorAgent(Agent): + """Special agent that marks steps as completed when executing them""" + + def __init__(self, memory: PlanAwareMemory, **kwargs): + super().__init__(**kwargs) + self.memory = memory + + async def run(self, input_data, **kwargs): + """Override run to update step status after execution""" + + # Get current plan and next steps + current_plan = self.memory.get_current_plan() + if current_plan: + next_steps = current_plan.get_next_steps() + + # Find steps assigned to this agent + my_steps = [step for step in next_steps if step.agent == self.name] + + if my_steps: + step = my_steps[0] # Execute first available step + print(f'⏳ Executing step: {step.id} - {step.description}') + + # Mark step as in progress + step.status = StepStatus.IN_PROGRESS + self.memory.update_plan(current_plan) + + # Execute the step using normal agent behavior + result = await super().run( + f'Execute this step: {step.description}. Context: {input_data}', + **kwargs, + ) + + # Mark step as completed + step.status = StepStatus.COMPLETED + step.result = result + self.memory.update_plan(current_plan) + + print(f'βœ… Completed step: {step.id}') + return result + + # If no steps to execute, just run normally + return await super().run(input_data, **kwargs) + + +async def run_fixed_demo(): + """Run the fixed plan-execute demo""" + print('πŸ”§ Fixed PlanExecuteRouter Demo') + print('=' * 40) + + # Check API key + api_key = os.getenv('OPENAI_API_KEY') + if not api_key: + print('❌ OPENAI_API_KEY environment variable not set') + print(' Set it with: export OPENAI_API_KEY=your_key_here') + return + + print('βœ… OpenAI API key found') + + # Create LLM + llm = OpenAI(model='gpt-4o', api_key=api_key) + + # Create plan-aware memory + memory = PlanAwareMemory() + + # Create special planner that stores ExecutionPlan objects + planner = PlannerAgent( + memory=memory, + name='planner', + system_prompt="""You are a project planner. Create execution plans in this EXACT format: + +EXECUTION PLAN: [Clear Title] +DESCRIPTION: [Brief description] + +STEPS: +1. step_1: [Description] β†’ developer +2. step_2: [Description] β†’ developer (depends on: step_1) +3. step_3: [Description] β†’ tester (depends on: step_2) +4. step_4: [Description] β†’ reviewer (depends on: step_3) + +Use only these agents: developer, tester, reviewer +Keep steps clear and actionable. +Always include dependencies where steps must be done in sequence.""", + llm=llm, + ) + + # Create executor agents that update step status + developer = ExecutorAgent( + memory=memory, + name='developer', + system_prompt="""You are a developer executing implementation steps. +Provide detailed implementation for the given step.""", + llm=llm, + ) + + tester = ExecutorAgent( + memory=memory, + name='tester', + system_prompt="""You are a tester validating implementations. +Create test scenarios and validate the implementation.""", + llm=llm, + ) + + reviewer = Agent( + name='reviewer', + system_prompt="""You are a reviewer providing final validation. +Review all completed work and give final approval.""", + llm=llm, + ) + + print('βœ… Created special agents with plan integration') + + # Create plan-execute router + plan_router = create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer', + additional_agents={'tester': 'Tests implementations'}, + llm=llm, + ) + + print('βœ… Created PlanExecuteRouter') + + # Create workflow + arium = ( + AriumBuilder() + .with_memory(memory) + .add_agents([planner, developer, tester, reviewer]) + .start_with(planner) + .add_edge(planner, [developer, tester, reviewer, planner], plan_router) + .add_edge(developer, [tester, reviewer, developer, planner], plan_router) + .add_edge(tester, [developer, reviewer, tester, planner], plan_router) + .add_edge(reviewer, [developer, tester, reviewer, planner], plan_router) + .end_with(reviewer) + .build() + ) + + print('βœ… Built Arium workflow') + + # Task to execute + task = 'Create a simple user login API endpoint' + + print(f'\nπŸ“‹ Task: {task}') + print('\nπŸ”„ Starting fixed plan-execute workflow...') + print(' This should now properly:') + print(' 1. Create and store execution plan') + print(' 2. Execute steps sequentially') + print(' 3. Track progress through completion') + + try: + # Execute workflow + result = await arium.run([task]) + + print('\n' + '=' * 50) + print('πŸŽ‰ WORKFLOW COMPLETED!') + print('=' * 50) + + # Show results + if result: + final_result = result[-1] if isinstance(result, list) else result + print('\nπŸ“„ Final Output:') + print('-' * 30) + print(final_result) + + # Show execution plan status + current_plan = memory.get_current_plan() + if current_plan: + print(f'\nπŸ“Š Final Plan Status: {current_plan.title}') + print(f'Completed: {current_plan.is_completed()}') + + print('\nπŸ“‹ Step Status:') + for step in current_plan.steps: + status_icon = { + StepStatus.PENDING: 'β—‹', + StepStatus.IN_PROGRESS: '⏳', + StepStatus.COMPLETED: 'βœ…', + StepStatus.FAILED: '❌', + }.get(step.status, 'β—‹') + print(f' {status_icon} {step.id}: {step.description} β†’ {step.agent}') + if step.result: + print(f' Result: {step.result[:100]}...') + + print('\nπŸ’‘ What was fixed:') + print(' β€’ PlannerAgent now creates and stores ExecutionPlan objects') + print(' β€’ ExecutorAgent updates step status during execution') + print(' β€’ Router can detect when plans exist in memory') + print(' β€’ No more infinite loops in the planner!') + + except Exception as e: + print(f'\n❌ Error: {e}') + print('Check the logs above for more details.') + + +async def run_simple_test(): + """Run a simple test to verify the fix works""" + print('\nπŸ“‹ Simple Plan Creation Test') + print('=' * 35) + + api_key = os.getenv('OPENAI_API_KEY') + if not api_key: + print('❌ OPENAI_API_KEY not set') + return + + # Create memory and planner + memory = PlanAwareMemory() + llm = OpenAI(model='gpt-4o', api_key=api_key) + + planner = PlannerAgent( + memory=memory, + name='planner', + system_prompt="""Create a plan in this format: + +EXECUTION PLAN: [Title] +DESCRIPTION: [Description] + +STEPS: +1. step_1: [Task] β†’ developer +2. step_2: [Task] β†’ tester (depends on: step_1) +3. step_3: [Task] β†’ reviewer (depends on: step_2)""", + llm=llm, + ) + + print('πŸ”„ Testing plan creation and storage...') + + try: + # Create a plan + await planner.run('Create a plan for building a simple calculator API') + + # Check if plan was stored + current_plan = memory.get_current_plan() + if current_plan: + print('βœ… Plan successfully created and stored!') + print(f'βœ… Title: {current_plan.title}') + print(f'βœ… Steps: {len(current_plan.steps)}') + + # Test next steps + next_steps = current_plan.get_next_steps() + print(f'βœ… Ready to execute: {len(next_steps)} steps') + + for step in next_steps: + print(f' β†’ {step.id}: {step.agent}') + else: + print('❌ Plan was not stored in memory') + + except Exception as e: + print(f'❌ Error: {e}') + + +def show_fix_explanation(): + """Explain what was fixed""" + print('\nπŸ”§ What Was Fixed') + print('=' * 20) + + explanation = """ +❌ Problem: Planner Loop +The original demo had the planner stuck in a loop because: +β€’ Planner generated plan text but didn't store ExecutionPlan objects +β€’ Router couldn't detect that a plan existed in memory +β€’ Router kept routing back to planner infinitely + +βœ… Solution: Special Agent Classes +Created specialized agents that integrate with PlanAwareMemory: +β€’ PlannerAgent: Parses plan text and stores ExecutionPlan objects +β€’ ExecutorAgent: Updates step status during execution +β€’ Proper integration between plan creation and execution + +🎯 Key Changes: +1. PlannerAgent.run() now creates and stores ExecutionPlan objects +2. ExecutorAgent.run() marks steps as in-progress/completed +3. Router can detect when plans exist and route accordingly +4. Proper step-by-step execution with status tracking + +πŸš€ Result: +β€’ No more infinite loops +β€’ Proper plan-execute workflow +β€’ Real-time step progress tracking +β€’ Seamless integration with PlanAwareMemory +""" + + print(explanation) + + +async def main(): + """Main demo function""" + print('🎯 Fixed PlanExecuteRouter Demo with Real OpenAI LLM') + print('This version fixes the planner loop issue!\n') + + if not os.getenv('OPENAI_API_KEY'): + print('❌ OPENAI_API_KEY not set') + print(' Set it with: export OPENAI_API_KEY=your_key_here') + return + + # Show what was fixed + show_fix_explanation() + + # Run tests + await run_simple_test() + await run_fixed_demo() + + print('\n\nπŸŽ‰ Fixed Demo Complete!') + print('The PlanExecuteRouter now works properly without infinite loops! πŸš€') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/flow_router_example.py b/flo_ai/examples/flow_router_example.py new file mode 100644 index 00000000..2da1e6c6 --- /dev/null +++ b/flo_ai/examples/flow_router_example.py @@ -0,0 +1,454 @@ +""" +Example demonstrating ReflectionRouter for A -> B -> A -> C patterns. + +This example shows how to implement a main -> critic -> main -> final reflection workflow +using the new ReflectionRouter with YAML configuration. +""" + +import asyncio +from flo_ai.arium.builder import AriumBuilder +from flo_ai.llm import OpenAI + +# Example YAML configuration for A -> B -> A -> C flow +MAIN_CRITIC_FLOW_YAML = """ +metadata: + name: main-critic-final-workflow + version: 1.0.0 + description: "A workflow demonstrating A -> B -> A -> C pattern with intelligent flow routing" + +arium: + agents: + - name: main_agent + role: Main Agent + job: > + You are the main agent responsible for analyzing tasks and creating initial solutions. + When you receive input, analyze it thoroughly and provide an initial response. + If you receive feedback from the critic, incorporate it to improve your work. + Be receptive to criticism and use it to refine your output. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.7 + + - name: critic + role: Critic Agent + job: > + You are a critic agent. Your job is to review the main agent's work and provide + constructive feedback. Analyze the output for: + - Accuracy and correctness + - Completeness and thoroughness + - Clarity and coherence + - Areas for improvement + Provide specific, actionable feedback that the main agent can use to improve. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + - name: final_agent + role: Final Agent + job: > + You are the final agent responsible for polishing and finalizing the work. + Take the refined output from the main agent (after critic feedback) and: + - Format it professionally + - Add any final touches or improvements + - Ensure it meets high quality standards + - Provide a polished final result + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.5 + + # Reflection router configuration for A -> B -> A -> C pattern + routers: + - name: main_critic_reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + allow_early_exit: false + fallback_strategy: first + + workflow: + start: main_agent + edges: + # Single edge from main_agent using reflection router + # The router will intelligently route to: critic -> main_agent -> final_agent + - from: main_agent + to: [critic, final_agent] # All possible destinations + router: main_critic_reflection_router + - from: critic + to: [main_agent, final_agent] + router: main_critic_reflection_router + - from: final_agent + to: [end] + end: [final_agent] +""" + +# Alternative stricter flow pattern +STRICT_FLOW_YAML = """ +metadata: + name: strict-main-critic-flow + version: 1.0.0 + description: "Strict A -> B -> A -> C flow with no deviations allowed" + +arium: + agents: + - name: writer + role: Content Writer + job: > + You are a content writer. Create initial content based on the user's request. + Focus on getting the core ideas down first, don't worry about perfection. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.8 + + - name: reviewer + role: Content Reviewer + job: > + You are a content reviewer. Review the writer's work and provide detailed feedback: + - What works well + - What needs improvement + - Specific suggestions for enhancement + - Areas that need clarification + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + + - name: editor + role: Content Editor + job: > + You are the final editor. Take the revised content from the writer and: + - Polish the language and style + - Ensure consistency and flow + - Make final corrections + - Prepare the content for publication + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + routers: + - name: strict_reflection_router + type: reflection + flow_pattern: [writer, reviewer, writer, editor] + settings: + allow_early_exit: false # Strict adherence to pattern + fallback_strategy: first + + workflow: + start: writer + edges: + - from: writer + to: [reviewer, editor] + router: strict_reflection_router + - from: reviewer + to: [writer, editor] + router: strict_reflection_router + - from: editor + to: [end] + end: [editor] +""" + +# Flexible flow that allows early exit +FLEXIBLE_FLOW_YAML = """ +metadata: + name: flexible-flow-with-early-exit + version: 1.0.0 + description: "Flexible A -> B -> A -> C flow that allows early completion" + +arium: + agents: + - name: analyst + role: Data Analyst + job: > + You are a data analyst. Analyze the given data or question and provide insights. + Create clear, actionable analysis based on the information provided. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.5 + + - name: validator + role: Analysis Validator + job: > + You are an analysis validator. Review the analyst's work for: + - Logical consistency + - Accuracy of conclusions + - Completeness of analysis + - Potential issues or gaps + If the analysis is solid, you can recommend proceeding directly to completion. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.1 + + - name: presenter + role: Results Presenter + job: > + You are a results presenter. Take the final analysis and create a professional + presentation of the findings with clear recommendations and next steps. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.4 + + routers: + - name: flexible_reflection_router + type: reflection + flow_pattern: [analyst, validator, analyst, presenter] + settings: + allow_early_exit: true # Allow skipping steps if appropriate + fallback_strategy: first + + workflow: + start: analyst + edges: + - from: analyst + to: [validator, presenter] + router: flexible_reflection_router + - from: validator + to: [analyst, presenter] + router: flexible_reflection_router + - from: presenter + to: [end] + end: [presenter] +""" + + +async def run_main_critic_flow_example(): + """Example 1: Main -> Critic -> Main -> Final flow""" + print('πŸš€ EXAMPLE 1: Main -> Critic -> Main -> Final Flow') + print('=' * 60) + + # Create workflow from YAML + builder = AriumBuilder.from_yaml( + yaml_str=MAIN_CRITIC_FLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), # Dummy key for demo + ) + + # Build the workflow + builder.build() + + print('βœ… Workflow built successfully!') + print('πŸ“‹ Reflection Pattern: main_agent β†’ critic β†’ main_agent β†’ final_agent') + print('🎯 The ReflectionRouter will:') + print(' 1. Start with main_agent for initial analysis') + print(' 2. Route to critic for feedback/reflection') + print(' 3. Return to main_agent for improvements') + print(' 4. Finally route to final_agent for polishing') + + # Test input + test_input = 'Write a comprehensive guide on sustainable urban planning' + print(f'\nπŸ“ Test Input: {test_input}') + print('πŸ’‘ This would follow the strict Aβ†’Bβ†’Aβ†’C pattern automatically!') + + +async def run_strict_flow_example(): + """Example 2: Strict flow with no deviations""" + print('\n\n🎯 EXAMPLE 2: Strict Writer -> Reviewer -> Writer -> Editor Flow') + print('=' * 70) + + builder = AriumBuilder.from_yaml( + yaml_str=STRICT_FLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + + print('βœ… Strict workflow built successfully!') + print('πŸ“‹ Flow Pattern: writer β†’ reviewer β†’ writer β†’ editor') + print('πŸ”’ Features:') + print(' β€’ Strict adherence to pattern (allow_early_exit: false)') + print(' β€’ LLM cannot deviate from the Aβ†’Bβ†’Aβ†’C sequence') + print(' β€’ Execution context tracks progress through flow') + + test_input = 'Create a blog post about renewable energy trends in 2024' + print(f'\nπŸ“ Test Input: {test_input}') + + +async def run_flexible_flow_example(): + """Example 3: Flexible flow with early exit option""" + print('\n\n🌟 EXAMPLE 3: Flexible Flow with Early Exit Option') + print('=' * 60) + + builder = AriumBuilder.from_yaml( + yaml_str=FLEXIBLE_FLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + + print('βœ… Flexible workflow built successfully!') + print('πŸ“‹ Flow Pattern: analyst β†’ validator β†’ analyst β†’ presenter') + print('πŸ”“ Features:') + print(' β€’ Flexible routing (allow_early_exit: true)') + print(' β€’ LLM can skip steps if analysis is already sufficient') + print(' β€’ Smart adaptation based on conversation context') + + test_input = 'Analyze the quarterly sales data and identify key trends' + print(f'\nπŸ“ Test Input: {test_input}') + + +def demonstrate_reflection_router_features(): + """Show the key features of ReflectionRouter""" + print('\n\nπŸ“‹ ReflectionRouter Key Features') + print('=' * 50) + + features = """ +🎯 Reflection Pattern Tracking: + β€’ Automatically tracks progress through defined reflection sequence + β€’ Uses execution context (node_visit_count) for intelligent routing + β€’ Prevents infinite loops while allowing intentional revisits + +πŸ“Š Visual Progress Display: + β€’ Shows current position in pattern: β—‹ pending, βœ“ completed + β€’ Displays suggested next step based on reflection pattern + β€’ Provides clear feedback on workflow state + +βš™οΈ Configuration Options: + β€’ allow_early_exit: Enable/disable smart reflection termination + β€’ flow_pattern: Define exact sequence (e.g., [main, critic, main, final]) + β€’ Standard LLM router settings (temperature, fallback_strategy) + +πŸ”„ Execution Context Awareness: + β€’ Tracks how many times each node has been visited + β€’ Calculates expected visits based on reflection pattern position + β€’ Intelligently determines next step in sequence + +πŸ“ YAML Configuration: + ```yaml + routers: + - name: my_reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + settings: + allow_early_exit: false + temperature: 0.2 + ``` + +πŸ›‘οΈ Safety Features: + β€’ Inherits anti-infinite-loop mechanisms from base router + β€’ Provides clear error messages for configuration issues + β€’ Graceful fallback when pattern completion detected +""" + + print(features) + + +def show_yaml_schema(): + """Show complete YAML schema for ReflectionRouter""" + print('\n\nπŸ“„ Complete ReflectionRouter YAML Schema') + print('=' * 50) + + schema = """ +# Complete example with ReflectionRouter +metadata: + name: my-flow-workflow + version: 1.0.0 + description: "A -> B -> A -> C flow pattern example" + +arium: + agents: + - name: main_agent + role: Main Agent + job: "Your main agent job description" + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.7 + + - name: critic + role: Critic + job: "Your critic agent job description" + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + - name: final_agent + role: Final Agent + job: "Your final agent job description" + model: + provider: openai + name: gpt-4o-mini + + routers: + - name: reflection_router + type: reflection # Router type + flow_pattern: [main_agent, critic, main_agent, final_agent] # A->B->A->C pattern + model: # Optional: LLM for routing decisions + provider: openai + name: gpt-4o-mini + settings: # Optional settings + temperature: 0.2 # Router temperature + allow_early_exit: false # Allow early completion + fallback_strategy: first # first, last, random + + workflow: + start: main_agent + edges: + - from: main_agent + to: [critic, final_agent] # All possible destinations + router: reflection_router # Use reflection router + - from: critic + to: [main_agent, final_agent] + router: reflection_router + - from: final_agent + to: [end] + end: [final_agent] +""" + print(schema) + + +async def main(): + """Run all examples""" + print('🌟 ReflectionRouter Examples - A β†’ B β†’ A β†’ C Pattern Implementation') + print('=' * 80) + print('This example demonstrates the new ReflectionRouter for implementing') + print('structured reflection patterns with intelligent LLM-based routing! πŸŽ‰') + + # Show features and schema first + demonstrate_reflection_router_features() + show_yaml_schema() + + # Run examples + await run_main_critic_flow_example() + await run_strict_flow_example() + await run_flexible_flow_example() + + print('\n\nπŸŽ‰ All ReflectionRouter examples completed!') + print('=' * 80) + print('βœ… ReflectionRouter Benefits:') + print(' β€’ Simple YAML configuration for complex reflection patterns') + print(' β€’ Automatic progress tracking through execution context') + print(' β€’ Intelligent routing decisions based on reflection state') + print(' β€’ Flexible vs strict reflection control options') + print(' β€’ Built-in safety features and loop prevention') + print(' β€’ Easy integration with existing Arium workflows') + + print('\nπŸš€ Try it yourself:') + print(' 1. Define your agents (main, critic, final)') + print(' 2. Create a reflection router with your pattern') + print(' 3. Configure workflow edges') + print(' 4. Run your Aβ†’Bβ†’Aβ†’C reflection workflow!') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/live_plan_execute_demo.py b/flo_ai/examples/live_plan_execute_demo.py new file mode 100644 index 00000000..bf56267f --- /dev/null +++ b/flo_ai/examples/live_plan_execute_demo.py @@ -0,0 +1,307 @@ +""" +Live PlanExecuteRouter Demo - Real OpenAI LLM Integration + +A focused demo showing PlanExecuteRouter with actual LLM calls. +Set OPENAI_API_KEY environment variable to run. + +This demonstrates: +1. Automatic task breakdown into execution plans +2. Step-by-step execution with progress tracking +3. Intelligent routing between planning and execution phases +""" + +import asyncio +import os +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.memory import PlanAwareMemory, ExecutionPlan, PlanStep, StepStatus +from flo_ai.arium.llm_router import create_plan_execute_router +from flo_ai.arium import AriumBuilder + + +class PlanParser: + """Helper to parse LLM-generated plans into ExecutionPlan objects""" + + @staticmethod + def parse_plan_from_text( + plan_text: str, planner_agent: str = 'planner' + ) -> ExecutionPlan: + """Parse structured plan text into ExecutionPlan object""" + import uuid + import re + + # Extract title and description + title_match = re.search(r'EXECUTION PLAN:\s*(.+)', plan_text) + title = title_match.group(1).strip() if title_match else 'Generated Plan' + + desc_match = re.search(r'DESCRIPTION:\s*(.+)', plan_text) + description = desc_match.group(1).strip() if desc_match else 'Execution plan' + + # Extract steps + steps = [] + step_pattern = ( + r'(\d+)\.\s*(\w+):\s*(.+?)\s*β†’\s*(\w+)(?:\s*\(depends on:\s*([^)]+)\))?' + ) + + for match in re.finditer(step_pattern, plan_text): + step_num, step_id, step_desc, agent, deps_str = match.groups() + + dependencies = [] + if deps_str: + dependencies = [dep.strip() for dep in deps_str.split(',')] + + step = PlanStep( + id=step_id, + description=step_desc.strip(), + agent=agent, + dependencies=dependencies, + status=StepStatus.PENDING, + ) + steps.append(step) + + return ExecutionPlan( + id=str(uuid.uuid4()), + title=title, + description=description, + steps=steps, + created_by=planner_agent, + ) + + +async def run_live_demo(): + """Run a live demo with real OpenAI API calls""" + print('πŸš€ Live PlanExecuteRouter Demo') + print('=' * 40) + + # Check API key + api_key = os.getenv('OPENAI_API_KEY') + if not api_key: + print('❌ OPENAI_API_KEY environment variable not set') + print(' Set it with: export OPENAI_API_KEY=your_key_here') + return + + print('βœ… OpenAI API key found') + + # Create LLM + llm = OpenAI(model='gpt-4o-mini', api_key=api_key) + + # Create agents with specific roles + planner = Agent( + name='planner', + system_prompt="""You are a project planner. Create execution plans in this exact format: + +EXECUTION PLAN: [Title] +DESCRIPTION: [Brief description] + +STEPS: +1. step_1: [Description] β†’ [agent] +2. step_2: [Description] β†’ [agent] (depends on: step_1) +3. step_3: [Description] β†’ [agent] (depends on: step_1, step_2) + +Use agents: developer, tester, reviewer +Keep steps clear and actionable.""", + llm=llm, + ) + + developer = Agent( + name='developer', + system_prompt="""You are a developer executing specific implementation steps. +Acknowledge the step you're working on and provide detailed implementation.""", + llm=llm, + ) + + tester = Agent( + name='tester', + system_prompt="""You are a tester validating implementations. +Create test scenarios and report validation results.""", + llm=llm, + ) + + reviewer = Agent( + name='reviewer', + system_prompt="""You are a reviewer providing final validation. +Review completed work and give final approval.""", + llm=llm, + ) + + print('βœ… Created agents: planner, developer, tester, reviewer') + + # Create memory and router + memory = PlanAwareMemory() + + plan_router = create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer', + additional_agents={'tester': 'Tests implementations'}, + llm=llm, + ) + + print('βœ… Created PlanExecuteRouter with PlanAwareMemory') + + # Create workflow + arium = ( + AriumBuilder() + .with_memory(memory) + .add_agents([planner, developer, tester, reviewer]) + .start_with(planner) + .add_edge(planner, [developer, tester, reviewer, planner], plan_router) + .add_edge(developer, [tester, reviewer, developer, planner], plan_router) + .add_edge(tester, [developer, reviewer, tester, planner], plan_router) + .add_edge(reviewer, [developer, tester, reviewer, planner], plan_router) + .end_with(reviewer) + .build() + ) + + print('βœ… Built Arium workflow') + + # Task to execute + task = 'Create a simple user registration API with email validation' + + print(f'\nπŸ“‹ Task: {task}') + print('\nπŸ”„ Executing plan-and-execute workflow...') + print( + ' Watch as the router coordinates planning β†’ development β†’ testing β†’ review' + ) + + try: + # Execute workflow + result = await arium.run([task]) + + print('\n' + '=' * 50) + print('πŸŽ‰ WORKFLOW COMPLETED!') + print('=' * 50) + + # Show results + if result: + final_result = result[-1] if isinstance(result, list) else result + print('\nπŸ“„ Final Output:') + print('-' * 30) + print(final_result) + + # Show execution plan if created + current_plan = memory.get_current_plan() + if current_plan: + print(f'\nπŸ“Š Execution Plan: {current_plan.title}') + print(f'Description: {current_plan.description}') + print(f'Steps: {len(current_plan.steps)}') + print(f'Completed: {current_plan.is_completed()}') + + print('\nπŸ“‹ Step Progress:') + for step in current_plan.steps: + status_icon = { + StepStatus.PENDING: 'β—‹', + StepStatus.IN_PROGRESS: '⏳', + StepStatus.COMPLETED: 'βœ…', + StepStatus.FAILED: '❌', + }.get(step.status, 'β—‹') + deps = ( + f" (deps: {', '.join(step.dependencies)})" + if step.dependencies + else '' + ) + print( + f' {status_icon} {step.id}: {step.description} β†’ {step.agent}{deps}' + ) + + print('\nπŸ’‘ What happened:') + print(' β€’ Router started by routing to planner') + print(' β€’ Planner created detailed execution plan') + print(' β€’ Router routed to developer for implementation steps') + print(' β€’ Router routed to tester for validation') + print(' β€’ Router routed to reviewer for final approval') + print(' β€’ Plan state tracked in PlanAwareMemory throughout') + + except Exception as e: + print(f'\n❌ Error: {e}') + print('This could be due to API rate limits or network issues.') + + +async def run_simple_plan_creation(): + """Demo just the plan creation part""" + print('\n\nπŸ“‹ Plan Creation Demo') + print('=' * 30) + + api_key = os.getenv('OPENAI_API_KEY') + if not api_key: + print('❌ OPENAI_API_KEY not set') + return + + llm = OpenAI(model='gpt-4o-mini', api_key=api_key) + + planner = Agent( + name='planner', + system_prompt="""Create an execution plan in this format: + +EXECUTION PLAN: [Title] +DESCRIPTION: [Description] + +STEPS: +1. step_1: [Task description] β†’ developer +2. step_2: [Task description] β†’ developer (depends on: step_1) +3. step_3: [Task description] β†’ tester (depends on: step_2) +4. step_4: [Task description] β†’ reviewer (depends on: step_3)""", + llm=llm, + ) + + task = 'Build a simple blog API with posts and comments' + print(f'Task: {task}') + print('\nπŸ”„ Generating execution plan...') + + try: + plan_text = await planner.run(f'Create a detailed execution plan for: {task}') + print('\nπŸ“‹ Generated Plan:') + print('-' * 30) + print(plan_text) + + # Parse into ExecutionPlan object + execution_plan = PlanParser.parse_plan_from_text(plan_text) + + print('\nβœ… Parsed into ExecutionPlan:') + print(f'Title: {execution_plan.title}') + print(f'Steps: {len(execution_plan.steps)}') + + for step in execution_plan.steps: + deps = ( + f" (depends: {', '.join(step.dependencies)})" + if step.dependencies + else '' + ) + print(f' β€’ {step.id}: {step.description} β†’ {step.agent}{deps}') + + except Exception as e: + print(f'❌ Error: {e}') + + +def show_setup_instructions(): + """Show how to set up and run the demo""" + print('πŸ“– Setup Instructions') + print('=' * 25) + print('1. Set your OpenAI API key:') + print(' export OPENAI_API_KEY=your_api_key_here') + print('\n2. Run the demo:') + print(' python examples/live_plan_execute_demo.py') + print('\n3. Watch the PlanExecuteRouter in action! πŸš€') + + +async def main(): + """Main demo function""" + print('🎯 Live PlanExecuteRouter Demo with Real OpenAI LLM') + print('This demo shows the full plan-and-execute workflow with actual API calls!\n') + + if not os.getenv('OPENAI_API_KEY'): + show_setup_instructions() + return + + # Run demos + await run_simple_plan_creation() + await run_live_demo() + + print('\n\nπŸŽ‰ Demo Complete!') + print( + 'You just saw PlanExecuteRouter break down a task and execute it step by step! πŸš€' + ) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/plan_execute_router_example.py b/flo_ai/examples/plan_execute_router_example.py new file mode 100644 index 00000000..a03132be --- /dev/null +++ b/flo_ai/examples/plan_execute_router_example.py @@ -0,0 +1,501 @@ +""" +Example demonstrating PlanExecuteRouter for Cursor-style plan-and-execute workflows. + +This example shows how to implement plan-and-execute patterns where tasks are broken down +into sequential steps and executed systematically, similar to how Cursor works. +""" + +import asyncio +from flo_ai.arium.builder import AriumBuilder +from flo_ai.llm import OpenAI + +# Example YAML configuration for Plan-Execute workflow +PLAN_EXECUTE_WORKFLOW_YAML = """ +metadata: + name: plan-execute-development-workflow + version: 1.0.0 + description: "Cursor-style plan-and-execute workflow for software development" + +arium: + agents: + - name: planner + role: Project Planner + job: > + You are a project planner who breaks down complex tasks into detailed, sequential steps. + Create comprehensive execution plans with clear dependencies and assigned agents. + Output your plan as a structured format that can be executed step by step. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + - name: developer + role: Software Developer + job: > + You are a software developer who implements code based on specific requirements. + Execute development tasks step by step, focusing on clean, maintainable code. + Report on progress and any issues encountered during implementation. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.5 + + - name: tester + role: Quality Assurance Tester + job: > + You are a QA tester who validates implementations and ensures quality. + Test code, identify bugs, and verify that requirements are met. + Provide detailed feedback on quality and functionality. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + + - name: reviewer + role: Code Reviewer + job: > + You are a code reviewer who provides final quality assessment. + Review completed work for best practices, maintainability, and correctness. + Provide final approval or request additional improvements. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.1 + + # Plan-Execute router configuration + routers: + - name: plan_execute_router + type: plan_execute + agents: + planner: "Creates detailed execution plans by breaking down tasks into sequential steps" + developer: "Implements code and features according to plan specifications" + tester: "Tests implementations and validates functionality" + reviewer: "Reviews and validates completed work for final approval" + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + planner_agent: planner + executor_agent: developer + reviewer_agent: reviewer + + workflow: + start: planner + edges: + - from: planner + to: [developer, tester, reviewer, planner] # All possible destinations + router: plan_execute_router + - from: developer + to: [tester, reviewer, developer, planner] + router: plan_execute_router + - from: tester + to: [developer, reviewer, tester, planner] + router: plan_execute_router + - from: reviewer + to: [end] + end: [reviewer] +""" + +# Simpler Plan-Execute workflow +SIMPLE_PLAN_EXECUTE_YAML = """ +metadata: + name: simple-plan-execute-workflow + version: 1.0.0 + description: "Simple plan-execute pattern for general tasks" + +arium: + agents: + - name: planner + role: Task Planner + job: > + Break down the given task into clear, actionable steps. + Create a detailed plan with dependencies and execution order. + model: + provider: openai + name: gpt-4o-mini + + - name: executor + role: Task Executor + job: > + Execute the steps from the plan one by one. + Focus on completing each step thoroughly before moving to the next. + model: + provider: openai + name: gpt-4o-mini + + - name: validator + role: Quality Validator + job: > + Validate that all steps have been completed correctly. + Ensure the final result meets the original requirements. + model: + provider: openai + name: gpt-4o-mini + + routers: + - name: simple_plan_router + type: plan_execute + agents: + planner: "Creates execution plans" + executor: "Executes plan steps" + validator: "Validates results" + settings: + planner_agent: planner + executor_agent: executor + reviewer_agent: validator + + workflow: + start: planner + edges: + - from: planner + to: [executor, validator, planner] + router: simple_plan_router + - from: executor + to: [validator, executor, planner] + router: simple_plan_router + - from: validator + to: [end] + end: [validator] +""" + +# Research workflow with plan-execute pattern +RESEARCH_PLAN_EXECUTE_YAML = """ +metadata: + name: research-plan-execute-workflow + version: 1.0.0 + description: "Plan-execute workflow for research projects" + +arium: + agents: + - name: research_planner + role: Research Planner + job: > + Create comprehensive research plans by breaking down research questions + into specific investigation steps, data collection tasks, and analysis phases. + model: + provider: openai + name: gpt-4o-mini + + - name: researcher + role: Researcher + job: > + Conduct research according to the plan. Gather information, analyze data, + and document findings for each step of the research plan. + model: + provider: openai + name: gpt-4o-mini + + - name: analyst + role: Data Analyst + job: > + Analyze research data and findings. Identify patterns, draw conclusions, + and prepare analytical insights based on the collected information. + model: + provider: openai + name: gpt-4o-mini + + - name: synthesizer + role: Research Synthesizer + job: > + Synthesize all research findings into a comprehensive final report. + Ensure all research questions are addressed and conclusions are well-supported. + model: + provider: openai + name: gpt-4o-mini + + routers: + - name: research_plan_router + type: plan_execute + agents: + research_planner: "Creates detailed research execution plans" + researcher: "Conducts research and gathers information" + analyst: "Analyzes data and identifies patterns" + synthesizer: "Creates final comprehensive reports" + settings: + planner_agent: research_planner + executor_agent: researcher + reviewer_agent: synthesizer + + workflow: + start: research_planner + edges: + - from: research_planner + to: [researcher, analyst, synthesizer, research_planner] + router: research_plan_router + - from: researcher + to: [analyst, synthesizer, researcher, research_planner] + router: research_plan_router + - from: analyst + to: [synthesizer, analyst, researcher, research_planner] + router: research_plan_router + - from: synthesizer + to: [end] + end: [synthesizer] +""" + + +async def run_development_workflow_example(): + """Example 1: Full development workflow with plan-execute pattern""" + print('πŸš€ EXAMPLE 1: Development Workflow with Plan-Execute Pattern') + print('=' * 65) + + # Create workflow from YAML + builder = AriumBuilder.from_yaml( + yaml_str=PLAN_EXECUTE_WORKFLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), # Dummy key for demo + ) + + # Build the workflow + builder.build() + + print('βœ… Development workflow built successfully!') + print('πŸ“‹ Plan-Execute Pattern: Planner β†’ Developer β†’ Tester β†’ Reviewer') + print('🎯 The PlanExecuteRouter will:') + print(' 1. Start with planner to create detailed execution plan') + print(' 2. Route to developer for step-by-step implementation') + print(' 3. Route to tester for quality validation') + print(' 4. Route to reviewer for final approval') + print(' 5. Track progress through each step with visual indicators') + + # Test input + test_input = 'Create a REST API for user authentication with JWT tokens' + print(f'\nπŸ“ Test Input: {test_input}') + print('πŸ’‘ Expected plan steps:') + print(' β—‹ Design API endpoints and data models') + print(' β—‹ Implement user registration endpoint') + print(' β—‹ Implement login endpoint with JWT generation') + print(' β—‹ Add authentication middleware') + print(' β—‹ Create comprehensive tests') + print(' β—‹ Review and optimize code') + + +async def run_simple_workflow_example(): + """Example 2: Simple plan-execute workflow""" + print('\n\n🎯 EXAMPLE 2: Simple Plan-Execute Workflow') + print('=' * 50) + + builder = AriumBuilder.from_yaml( + yaml_str=SIMPLE_PLAN_EXECUTE_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + + print('βœ… Simple workflow built successfully!') + print('πŸ“‹ Plan-Execute Pattern: Planner β†’ Executor β†’ Validator') + print('🎯 Features:') + print(' β€’ Automatic task breakdown by planner') + print(' β€’ Sequential step execution') + print(' β€’ Progress tracking with plan state management') + print(' β€’ Quality validation before completion') + + test_input = 'Organize a team building event for 20 people' + print(f'\nπŸ“ Test Input: {test_input}') + print('πŸ’‘ Expected workflow:') + print(' 1. Planner creates detailed event plan') + print(' 2. Executor handles each step (venue, catering, activities)') + print(' 3. Validator ensures everything is properly organized') + + +async def run_research_workflow_example(): + """Example 3: Research workflow with plan-execute pattern""" + print('\n\nπŸ”¬ EXAMPLE 3: Research Plan-Execute Workflow') + print('=' * 50) + + builder = AriumBuilder.from_yaml( + yaml_str=RESEARCH_PLAN_EXECUTE_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + + print('βœ… Research workflow built successfully!') + print( + 'πŸ“‹ Plan-Execute Pattern: Research Planner β†’ Researcher β†’ Analyst β†’ Synthesizer' + ) + print('🎯 Features:') + print(' β€’ Structured research methodology') + print(' β€’ Data collection and analysis phases') + print(' β€’ Comprehensive synthesis and reporting') + print(' β€’ Academic-quality research process') + + test_input = 'Research the impact of remote work on employee productivity' + print(f'\nπŸ“ Test Input: {test_input}') + print('πŸ’‘ Expected research plan:') + print(' β—‹ Literature review on remote work studies') + print(' β—‹ Survey design and data collection') + print(' β—‹ Statistical analysis of productivity metrics') + print(' β—‹ Qualitative analysis of employee feedback') + print(' β—‹ Final report with recommendations') + + +def demonstrate_plan_execute_features(): + """Show the key features of PlanExecuteRouter""" + print('\n\nπŸ“‹ PlanExecuteRouter Key Features') + print('=' * 45) + + features = """ +🎯 Cursor-Style Planning: + β€’ Automatic task breakdown into sequential steps + β€’ Dependency tracking between steps + β€’ Agent assignment for each step + β€’ Progress visualization with status indicators + +πŸ“Š Plan Management: + β€’ ExecutionPlan storage in enhanced memory + β€’ Step status tracking (pending, in_progress, completed, failed) + β€’ Automatic next-step determination + β€’ Failed step recovery and retry logic + +πŸ”„ Execution Flow: + β€’ Phase 1: Planning (create detailed execution plan) + β€’ Phase 2: Execution (complete steps sequentially) + β€’ Phase 3: Review (validate final results) + β€’ Automatic routing between phases + +βš™οΈ Configuration Options: + β€’ agents: Define available agents and their capabilities + β€’ planner_agent: Agent responsible for creating plans + β€’ executor_agent: Default agent for executing steps + β€’ reviewer_agent: Optional agent for final review + +πŸ›‘οΈ Safety Features: + β€’ Prevents infinite loops with step completion tracking + β€’ Handles failed steps with recovery mechanisms + β€’ Memory persistence for plan state + β€’ Execution context awareness + +πŸ“ YAML Configuration: + ```yaml + routers: + - name: plan_execute_router + type: plan_execute + agents: + planner: "Creates execution plans" + developer: "Implements features" + tester: "Validates quality" + settings: + planner_agent: planner + executor_agent: developer + reviewer_agent: tester + ``` + +πŸ”§ Memory Integration: + β€’ Uses PlanAwareMemory for plan storage + β€’ Automatic plan state persistence + β€’ Step result tracking and history + β€’ Context sharing between execution steps +""" + + print(features) + + +def show_yaml_schema(): + """Show complete YAML schema for PlanExecuteRouter""" + print('\n\nπŸ“„ Complete PlanExecuteRouter YAML Schema') + print('=' * 55) + + schema = """ +# Complete example with PlanExecuteRouter +metadata: + name: my-plan-execute-workflow + version: 1.0.0 + description: "Cursor-style plan-and-execute workflow" + +arium: + agents: + - name: planner + role: "Task Planner" + job: "Create detailed execution plans" + model: + provider: openai + name: gpt-4o-mini + + - name: executor + role: "Task Executor" + job: "Execute plan steps systematically" + model: + provider: openai + name: gpt-4o-mini + + - name: reviewer + role: "Quality Reviewer" + job: "Review and validate final results" + model: + provider: openai + name: gpt-4o-mini + + routers: + - name: plan_execute_router + type: plan_execute # Router type + agents: # Required: Available agents + planner: "Creates detailed execution plans" + executor: "Executes individual plan steps" + reviewer: "Reviews final results" + specialist: "Handles specialized tasks" + model: # Optional: LLM for routing + provider: openai + name: gpt-4o-mini + settings: # Optional settings + temperature: 0.2 # Router temperature + planner_agent: planner # Agent for creating plans + executor_agent: executor # Default execution agent + reviewer_agent: reviewer # Optional review agent + max_retries: 3 # Max retries for failed steps + + workflow: + start: planner + edges: + - from: planner + to: [executor, reviewer, specialist, planner] # All possible destinations + router: plan_execute_router + - from: executor + to: [reviewer, specialist, executor, planner] + router: plan_execute_router + - from: reviewer + to: [end] + end: [reviewer] +""" + print(schema) + + +async def main(): + """Run all examples""" + print('🌟 PlanExecuteRouter Examples - Cursor-Style Plan-and-Execute Workflows') + print('=' * 85) + print('This example demonstrates the new PlanExecuteRouter for implementing') + print('sophisticated plan-and-execute patterns with intelligent step tracking! πŸŽ‰') + + # Show features and schema first + demonstrate_plan_execute_features() + show_yaml_schema() + + # Run examples + await run_development_workflow_example() + await run_simple_workflow_example() + await run_research_workflow_example() + + print('\n\nπŸŽ‰ All PlanExecuteRouter examples completed!') + print('=' * 85) + print('βœ… PlanExecuteRouter Benefits:') + print(' β€’ Cursor-style automatic task breakdown and execution') + print(' β€’ Intelligent step-by-step progress tracking') + print(' β€’ Visual progress indicators with plan state management') + print(' β€’ Automatic routing based on execution plan progress') + print(' β€’ Built-in error handling and step retry mechanisms') + print(' β€’ Enhanced memory system with plan persistence') + + print('\nπŸš€ Try it yourself:') + print(' 1. Define your planner, executor, and reviewer agents') + print(' 2. Create a plan-execute router with agent mappings') + print(' 3. Use PlanAwareMemory for plan state persistence') + print(' 4. Run complex tasks with automatic breakdown!') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/reflection_router_example.py b/flo_ai/examples/reflection_router_example.py new file mode 100644 index 00000000..2da1e6c6 --- /dev/null +++ b/flo_ai/examples/reflection_router_example.py @@ -0,0 +1,454 @@ +""" +Example demonstrating ReflectionRouter for A -> B -> A -> C patterns. + +This example shows how to implement a main -> critic -> main -> final reflection workflow +using the new ReflectionRouter with YAML configuration. +""" + +import asyncio +from flo_ai.arium.builder import AriumBuilder +from flo_ai.llm import OpenAI + +# Example YAML configuration for A -> B -> A -> C flow +MAIN_CRITIC_FLOW_YAML = """ +metadata: + name: main-critic-final-workflow + version: 1.0.0 + description: "A workflow demonstrating A -> B -> A -> C pattern with intelligent flow routing" + +arium: + agents: + - name: main_agent + role: Main Agent + job: > + You are the main agent responsible for analyzing tasks and creating initial solutions. + When you receive input, analyze it thoroughly and provide an initial response. + If you receive feedback from the critic, incorporate it to improve your work. + Be receptive to criticism and use it to refine your output. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.7 + + - name: critic + role: Critic Agent + job: > + You are a critic agent. Your job is to review the main agent's work and provide + constructive feedback. Analyze the output for: + - Accuracy and correctness + - Completeness and thoroughness + - Clarity and coherence + - Areas for improvement + Provide specific, actionable feedback that the main agent can use to improve. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + - name: final_agent + role: Final Agent + job: > + You are the final agent responsible for polishing and finalizing the work. + Take the refined output from the main agent (after critic feedback) and: + - Format it professionally + - Add any final touches or improvements + - Ensure it meets high quality standards + - Provide a polished final result + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.5 + + # Reflection router configuration for A -> B -> A -> C pattern + routers: + - name: main_critic_reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + allow_early_exit: false + fallback_strategy: first + + workflow: + start: main_agent + edges: + # Single edge from main_agent using reflection router + # The router will intelligently route to: critic -> main_agent -> final_agent + - from: main_agent + to: [critic, final_agent] # All possible destinations + router: main_critic_reflection_router + - from: critic + to: [main_agent, final_agent] + router: main_critic_reflection_router + - from: final_agent + to: [end] + end: [final_agent] +""" + +# Alternative stricter flow pattern +STRICT_FLOW_YAML = """ +metadata: + name: strict-main-critic-flow + version: 1.0.0 + description: "Strict A -> B -> A -> C flow with no deviations allowed" + +arium: + agents: + - name: writer + role: Content Writer + job: > + You are a content writer. Create initial content based on the user's request. + Focus on getting the core ideas down first, don't worry about perfection. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.8 + + - name: reviewer + role: Content Reviewer + job: > + You are a content reviewer. Review the writer's work and provide detailed feedback: + - What works well + - What needs improvement + - Specific suggestions for enhancement + - Areas that need clarification + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + + - name: editor + role: Content Editor + job: > + You are the final editor. Take the revised content from the writer and: + - Polish the language and style + - Ensure consistency and flow + - Make final corrections + - Prepare the content for publication + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + routers: + - name: strict_reflection_router + type: reflection + flow_pattern: [writer, reviewer, writer, editor] + settings: + allow_early_exit: false # Strict adherence to pattern + fallback_strategy: first + + workflow: + start: writer + edges: + - from: writer + to: [reviewer, editor] + router: strict_reflection_router + - from: reviewer + to: [writer, editor] + router: strict_reflection_router + - from: editor + to: [end] + end: [editor] +""" + +# Flexible flow that allows early exit +FLEXIBLE_FLOW_YAML = """ +metadata: + name: flexible-flow-with-early-exit + version: 1.0.0 + description: "Flexible A -> B -> A -> C flow that allows early completion" + +arium: + agents: + - name: analyst + role: Data Analyst + job: > + You are a data analyst. Analyze the given data or question and provide insights. + Create clear, actionable analysis based on the information provided. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.5 + + - name: validator + role: Analysis Validator + job: > + You are an analysis validator. Review the analyst's work for: + - Logical consistency + - Accuracy of conclusions + - Completeness of analysis + - Potential issues or gaps + If the analysis is solid, you can recommend proceeding directly to completion. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.1 + + - name: presenter + role: Results Presenter + job: > + You are a results presenter. Take the final analysis and create a professional + presentation of the findings with clear recommendations and next steps. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.4 + + routers: + - name: flexible_reflection_router + type: reflection + flow_pattern: [analyst, validator, analyst, presenter] + settings: + allow_early_exit: true # Allow skipping steps if appropriate + fallback_strategy: first + + workflow: + start: analyst + edges: + - from: analyst + to: [validator, presenter] + router: flexible_reflection_router + - from: validator + to: [analyst, presenter] + router: flexible_reflection_router + - from: presenter + to: [end] + end: [presenter] +""" + + +async def run_main_critic_flow_example(): + """Example 1: Main -> Critic -> Main -> Final flow""" + print('πŸš€ EXAMPLE 1: Main -> Critic -> Main -> Final Flow') + print('=' * 60) + + # Create workflow from YAML + builder = AriumBuilder.from_yaml( + yaml_str=MAIN_CRITIC_FLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), # Dummy key for demo + ) + + # Build the workflow + builder.build() + + print('βœ… Workflow built successfully!') + print('πŸ“‹ Reflection Pattern: main_agent β†’ critic β†’ main_agent β†’ final_agent') + print('🎯 The ReflectionRouter will:') + print(' 1. Start with main_agent for initial analysis') + print(' 2. Route to critic for feedback/reflection') + print(' 3. Return to main_agent for improvements') + print(' 4. Finally route to final_agent for polishing') + + # Test input + test_input = 'Write a comprehensive guide on sustainable urban planning' + print(f'\nπŸ“ Test Input: {test_input}') + print('πŸ’‘ This would follow the strict Aβ†’Bβ†’Aβ†’C pattern automatically!') + + +async def run_strict_flow_example(): + """Example 2: Strict flow with no deviations""" + print('\n\n🎯 EXAMPLE 2: Strict Writer -> Reviewer -> Writer -> Editor Flow') + print('=' * 70) + + builder = AriumBuilder.from_yaml( + yaml_str=STRICT_FLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + + print('βœ… Strict workflow built successfully!') + print('πŸ“‹ Flow Pattern: writer β†’ reviewer β†’ writer β†’ editor') + print('πŸ”’ Features:') + print(' β€’ Strict adherence to pattern (allow_early_exit: false)') + print(' β€’ LLM cannot deviate from the Aβ†’Bβ†’Aβ†’C sequence') + print(' β€’ Execution context tracks progress through flow') + + test_input = 'Create a blog post about renewable energy trends in 2024' + print(f'\nπŸ“ Test Input: {test_input}') + + +async def run_flexible_flow_example(): + """Example 3: Flexible flow with early exit option""" + print('\n\n🌟 EXAMPLE 3: Flexible Flow with Early Exit Option') + print('=' * 60) + + builder = AriumBuilder.from_yaml( + yaml_str=FLEXIBLE_FLOW_YAML, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + + print('βœ… Flexible workflow built successfully!') + print('πŸ“‹ Flow Pattern: analyst β†’ validator β†’ analyst β†’ presenter') + print('πŸ”“ Features:') + print(' β€’ Flexible routing (allow_early_exit: true)') + print(' β€’ LLM can skip steps if analysis is already sufficient') + print(' β€’ Smart adaptation based on conversation context') + + test_input = 'Analyze the quarterly sales data and identify key trends' + print(f'\nπŸ“ Test Input: {test_input}') + + +def demonstrate_reflection_router_features(): + """Show the key features of ReflectionRouter""" + print('\n\nπŸ“‹ ReflectionRouter Key Features') + print('=' * 50) + + features = """ +🎯 Reflection Pattern Tracking: + β€’ Automatically tracks progress through defined reflection sequence + β€’ Uses execution context (node_visit_count) for intelligent routing + β€’ Prevents infinite loops while allowing intentional revisits + +πŸ“Š Visual Progress Display: + β€’ Shows current position in pattern: β—‹ pending, βœ“ completed + β€’ Displays suggested next step based on reflection pattern + β€’ Provides clear feedback on workflow state + +βš™οΈ Configuration Options: + β€’ allow_early_exit: Enable/disable smart reflection termination + β€’ flow_pattern: Define exact sequence (e.g., [main, critic, main, final]) + β€’ Standard LLM router settings (temperature, fallback_strategy) + +πŸ”„ Execution Context Awareness: + β€’ Tracks how many times each node has been visited + β€’ Calculates expected visits based on reflection pattern position + β€’ Intelligently determines next step in sequence + +πŸ“ YAML Configuration: + ```yaml + routers: + - name: my_reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + settings: + allow_early_exit: false + temperature: 0.2 + ``` + +πŸ›‘οΈ Safety Features: + β€’ Inherits anti-infinite-loop mechanisms from base router + β€’ Provides clear error messages for configuration issues + β€’ Graceful fallback when pattern completion detected +""" + + print(features) + + +def show_yaml_schema(): + """Show complete YAML schema for ReflectionRouter""" + print('\n\nπŸ“„ Complete ReflectionRouter YAML Schema') + print('=' * 50) + + schema = """ +# Complete example with ReflectionRouter +metadata: + name: my-flow-workflow + version: 1.0.0 + description: "A -> B -> A -> C flow pattern example" + +arium: + agents: + - name: main_agent + role: Main Agent + job: "Your main agent job description" + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.7 + + - name: critic + role: Critic + job: "Your critic agent job description" + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + + - name: final_agent + role: Final Agent + job: "Your final agent job description" + model: + provider: openai + name: gpt-4o-mini + + routers: + - name: reflection_router + type: reflection # Router type + flow_pattern: [main_agent, critic, main_agent, final_agent] # A->B->A->C pattern + model: # Optional: LLM for routing decisions + provider: openai + name: gpt-4o-mini + settings: # Optional settings + temperature: 0.2 # Router temperature + allow_early_exit: false # Allow early completion + fallback_strategy: first # first, last, random + + workflow: + start: main_agent + edges: + - from: main_agent + to: [critic, final_agent] # All possible destinations + router: reflection_router # Use reflection router + - from: critic + to: [main_agent, final_agent] + router: reflection_router + - from: final_agent + to: [end] + end: [final_agent] +""" + print(schema) + + +async def main(): + """Run all examples""" + print('🌟 ReflectionRouter Examples - A β†’ B β†’ A β†’ C Pattern Implementation') + print('=' * 80) + print('This example demonstrates the new ReflectionRouter for implementing') + print('structured reflection patterns with intelligent LLM-based routing! πŸŽ‰') + + # Show features and schema first + demonstrate_reflection_router_features() + show_yaml_schema() + + # Run examples + await run_main_critic_flow_example() + await run_strict_flow_example() + await run_flexible_flow_example() + + print('\n\nπŸŽ‰ All ReflectionRouter examples completed!') + print('=' * 80) + print('βœ… ReflectionRouter Benefits:') + print(' β€’ Simple YAML configuration for complex reflection patterns') + print(' β€’ Automatic progress tracking through execution context') + print(' β€’ Intelligent routing decisions based on reflection state') + print(' β€’ Flexible vs strict reflection control options') + print(' β€’ Built-in safety features and loop prevention') + print(' β€’ Easy integration with existing Arium workflows') + + print('\nπŸš€ Try it yourself:') + print(' 1. Define your agents (main, critic, final)') + print(' 2. Create a reflection router with your pattern') + print(' 3. Configure workflow edges') + print(' 4. Run your Aβ†’Bβ†’Aβ†’C reflection workflow!') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/simple_flow_router_demo.py b/flo_ai/examples/simple_flow_router_demo.py new file mode 100644 index 00000000..8b917b60 --- /dev/null +++ b/flo_ai/examples/simple_flow_router_demo.py @@ -0,0 +1,181 @@ +""" +Simple demonstration of ReflectionRouter for A -> B -> A -> C patterns. + +This shows the minimal code needed to implement a main -> critic -> main -> final +reflection pattern using the new ReflectionRouter. +""" + +import asyncio +from flo_ai.arium.builder import AriumBuilder +from flo_ai.arium.memory import MessageMemory +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.llm_router import create_main_critic_reflection_router + + +async def simple_reflection_demo(): + """Minimal example of A -> B -> A -> C reflection pattern""" + print('πŸš€ Simple ReflectionRouter Demo: A β†’ B β†’ A β†’ C Pattern') + print('=' * 60) + + # Create LLM (use dummy key for demo) + llm = OpenAI(model='gpt-4o-mini', api_key='dummy-key') + + # Create agents + main_agent = Agent( + name='main_agent', + system_prompt='You are the main agent. Analyze tasks and create solutions.', + llm=llm, + ) + + critic = Agent( + name='critic', + system_prompt='You are a critic. Provide constructive feedback to improve work.', + llm=llm, + ) + + final_agent = Agent( + name='final_agent', + system_prompt='You are the final agent. Polish and finalize the work.', + llm=llm, + ) + + # Create reflection router for A -> B -> A -> C pattern + reflection_router = create_main_critic_reflection_router( + main_agent='main_agent', + critic_agent='critic', + final_agent='final_agent', + allow_early_exit=False, # Strict reflection + llm=llm, + ) + + # Build workflow + builder = ( + AriumBuilder() + .with_memory(MessageMemory()) + .add_agents([main_agent, critic, final_agent]) + .start_with(main_agent) + .add_edge(main_agent, [critic, final_agent], reflection_router) + .add_edge(critic, [main_agent, final_agent], reflection_router) + .end_with(final_agent) + ) + + # Build the Arium + arium = builder.build() + + print('βœ… Workflow created successfully!') + print('πŸ“‹ Reflection Pattern: main_agent β†’ critic β†’ main_agent β†’ final_agent') + print('🎯 Router will automatically follow this sequence') + + # Demo input + print('\nπŸ“ Example input: "Create a project plan for a mobile app"') + print('πŸ’‘ The reflection router will:') + print(' Step 1: Route to critic (for feedback/reflection)') + print(' Step 2: Return to main_agent (to incorporate feedback)') + print(' Step 3: Route to final_agent (for final polish)') + + return arium + + +async def programmatic_reflection_example(): + """Show how to create reflection router programmatically""" + print('\n\nπŸ”§ Programmatic ReflectionRouter Creation') + print('=' * 50) + + from flo_ai.arium.llm_router import create_llm_router + + # Method 1: Using the convenience function + create_main_critic_reflection_router( + main_agent='writer', critic_agent='reviewer', final_agent='editor' + ) + print('βœ… Method 1: Convenience function create_main_critic_reflection_router()') + + # Method 2: Using the factory function directly + create_llm_router( + 'reflection', + flow_pattern=['analyst', 'validator', 'analyst', 'presenter'], + allow_early_exit=True, + ) + print('βœ… Method 2: Factory function create_llm_router(type="reflection")') + + # Method 3: Creating ReflectionRouter directly + from flo_ai.arium.llm_router import ReflectionRouter + + ReflectionRouter( + flow_pattern=['main', 'critic', 'main', 'final'], allow_early_exit=False + ) + print('βœ… Method 3: Direct ReflectionRouter instantiation') + + print('\n🎯 All methods create the same Aβ†’Bβ†’Aβ†’C reflection pattern!') + + +def show_minimal_yaml(): + """Show the minimal YAML needed""" + print('\n\nπŸ“„ Minimal YAML Configuration') + print('=' * 35) + + yaml_example = """ +# Minimal ReflectionRouter YAML +arium: + agents: + - name: main_agent + job: "Main agent job" + model: {provider: openai, name: gpt-4o-mini} + - name: critic + job: "Critic job" + model: {provider: openai, name: gpt-4o-mini} + - name: final_agent + job: "Final agent job" + model: {provider: openai, name: gpt-4o-mini} + + routers: + - name: reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + + workflow: + start: main_agent + edges: + - from: main_agent + to: [critic, final_agent] + router: reflection_router + - from: critic + to: [main_agent, final_agent] + router: reflection_router + - from: final_agent + to: [end] + end: [final_agent] +""" + print(yaml_example) + + +async def main(): + """Run the simple demo""" + print('🌟 Simple ReflectionRouter Demo') + print('=' * 35) + print('Demonstrating A β†’ B β†’ A β†’ C reflection pattern with minimal setup\n') + + # Show different creation methods + await programmatic_reflection_example() + + # Show minimal YAML + show_minimal_yaml() + + # Create simple reflection workflow + arium = await simple_reflection_demo() + + print('\n\nπŸŽ‰ Demo completed!') + print('Key takeaways:') + print('βœ… ReflectionRouter makes Aβ†’Bβ†’Aβ†’C patterns trivial to implement') + print('βœ… Works with both YAML and programmatic configuration') + print('βœ… Automatically tracks progress and prevents infinite loops') + print('βœ… Provides intelligent routing based on execution context') + + result = await arium.run( + inputs=['Write a comprehensive guide on sustainable urban planning'] + ) + print(result) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/simple_plan_execute_demo.py b/flo_ai/examples/simple_plan_execute_demo.py new file mode 100644 index 00000000..0b4e5607 --- /dev/null +++ b/flo_ai/examples/simple_plan_execute_demo.py @@ -0,0 +1,418 @@ +""" +Simple demonstration of PlanExecuteRouter with actual plan creation and execution. + +This demo shows how the PlanExecuteRouter works with PlanAwareMemory to create, +store, and execute plans step by step, similar to how Cursor works. +""" + +import asyncio +import uuid +from flo_ai.arium.builder import AriumBuilder +from flo_ai.arium.memory import PlanAwareMemory, ExecutionPlan, PlanStep, StepStatus +from flo_ai.llm import OpenAI +from flo_ai.models.agent import Agent +from flo_ai.arium.llm_router import create_plan_execute_router + + +async def demo_plan_aware_memory(): + """Demonstrate PlanAwareMemory functionality""" + print('πŸ“‹ DEMO: PlanAwareMemory - Plan Storage and Management') + print('=' * 55) + + # Create plan-aware memory + memory = PlanAwareMemory() + + # Create a sample execution plan + plan = ExecutionPlan( + id=str(uuid.uuid4()), + title='Build User Authentication System', + description='Create a complete user authentication system with login, registration, and JWT tokens', + steps=[ + PlanStep( + id='step_1', + description='Design database schema for users', + agent='developer', + status=StepStatus.PENDING, + ), + PlanStep( + id='step_2', + description='Implement user registration endpoint', + agent='developer', + dependencies=['step_1'], + status=StepStatus.PENDING, + ), + PlanStep( + id='step_3', + description='Implement login endpoint with JWT generation', + agent='developer', + dependencies=['step_1', 'step_2'], + status=StepStatus.PENDING, + ), + PlanStep( + id='step_4', + description='Add authentication middleware', + agent='developer', + dependencies=['step_3'], + status=StepStatus.PENDING, + ), + PlanStep( + id='step_5', + description='Write comprehensive tests', + agent='tester', + dependencies=['step_4'], + status=StepStatus.PENDING, + ), + PlanStep( + id='step_6', + description='Final code review and optimization', + agent='reviewer', + dependencies=['step_5'], + status=StepStatus.PENDING, + ), + ], + ) + + # Add plan to memory + memory.add_plan(plan) + print(f'βœ… Plan added to memory: {plan.title}') + print(f'πŸ“Š Total steps: {len(plan.steps)}') + + # Show plan progress + def show_progress(): + current_plan = memory.get_current_plan() + if current_plan: + print(f'\nπŸ“‹ Plan Progress: {current_plan.title}') + for step in current_plan.steps: + status_icon = { + StepStatus.PENDING: 'β—‹', + StepStatus.IN_PROGRESS: '⏳', + StepStatus.COMPLETED: 'βœ…', + StepStatus.FAILED: '❌', + }.get(step.status, 'β—‹') + deps = ( + f" (depends on: {', '.join(step.dependencies)})" + if step.dependencies + else '' + ) + print( + f' {status_icon} {step.id}: {step.description} β†’ {step.agent}{deps}' + ) + + show_progress() + + # Simulate step execution + print('\nπŸ”„ Simulating step execution...') + + # Execute step 1 + current_plan = memory.get_current_plan() + next_steps = current_plan.get_next_steps() + if next_steps: + step = next_steps[0] + print(f'\n⏳ Executing: {step.description}') + step.status = StepStatus.IN_PROGRESS + memory.update_plan(current_plan) + + # Simulate completion + step.status = StepStatus.COMPLETED + step.result = ( + 'User table created with id, email, password_hash, created_at fields' + ) + memory.update_plan(current_plan) + print(f'βœ… Completed: {step.description}') + + # Execute step 2 + current_plan = memory.get_current_plan() + next_steps = current_plan.get_next_steps() + if next_steps: + step = next_steps[0] + print(f'\n⏳ Executing: {step.description}') + step.status = StepStatus.COMPLETED + step.result = 'POST /api/register endpoint implemented with validation' + memory.update_plan(current_plan) + print(f'βœ… Completed: {step.description}') + + show_progress() + + # Check what's next + current_plan = memory.get_current_plan() + next_steps = current_plan.get_next_steps() + print(f'\n🎯 Next steps ready for execution: {len(next_steps)}') + for step in next_steps: + print(f' β†’ {step.id}: {step.description} (agent: {step.agent})') + + print(f'\nπŸ“ˆ Plan completion: {current_plan.is_completed()}') + + +async def demo_programmatic_plan_execute(): + """Demonstrate programmatic usage of PlanExecuteRouter""" + print('\n\nπŸ—οΈ DEMO: Programmatic PlanExecuteRouter Usage') + print('=' * 55) + + # Create LLM with dummy key for demo + llm = OpenAI(model='gpt-4o-mini', api_key='dummy-key') + + # Create agents + Agent( + name='planner', + system_prompt="""You are an expert project planner. When given a task, create a detailed execution plan. + +When asked to create a plan, respond with a structured format like this: + +EXECUTION PLAN: [Title] +DESCRIPTION: [Brief description] + +STEPS: +1. step_id: [description] β†’ [agent_name] +2. step_id: [description] β†’ [agent_name] (depends on: step1) +3. step_id: [description] β†’ [agent_name] (depends on: step1, step2) + +Always include clear dependencies and assign appropriate agents.""", + llm=llm, + ) + + Agent( + name='developer', + system_prompt='You are a software developer. Execute development tasks step by step.', + llm=llm, + ) + + Agent( + name='tester', + system_prompt='You are a QA tester. Test implementations and validate functionality.', + llm=llm, + ) + + Agent( + name='reviewer', + system_prompt='You are a code reviewer. Review completed work and provide final validation.', + llm=llm, + ) + + # Create plan-execute router + plan_router = create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer', + additional_agents={ + 'tester': 'Tests implementations and validates functionality' + }, + llm=llm, + ) + + # Create plan-aware memory + memory = PlanAwareMemory() + + print('βœ… Created agents and PlanExecuteRouter') + print('🎯 Router will coordinate: planner β†’ developer β†’ tester β†’ reviewer') + print('πŸ’Ύ Using PlanAwareMemory for plan state management') + + # Simulate routing decisions + print('\n🧠 Simulating router decision making...') + + # Add a message to trigger planning + memory.add({'role': 'user', 'content': 'Create a TODO app with React and Node.js'}) + + # Test routing with no plan (should route to planner) + try: + next_agent = plan_router(memory) + print(f'πŸ“ Router decision (no plan): {next_agent}') + print(' Expected: planner (to create execution plan)') + + except Exception as e: + print(f'⚠️ Router simulation note: {e}') + print(' (This is expected in demo mode without real LLM calls)') + + print('\nπŸ’‘ In a real scenario:') + print(' 1. Router would route to planner to create execution plan') + print(' 2. Planner creates detailed plan and stores in memory') + print(' 3. Router routes to developer for first development step') + print(' 4. Developer completes step and updates plan status') + print(' 5. Router routes to next step based on plan state') + print(' 6. Process continues until all steps complete') + print(' 7. Router routes to reviewer for final validation') + + +async def demo_yaml_plan_execute(): + """Demonstrate YAML configuration for PlanExecuteRouter""" + print('\n\nπŸ“„ DEMO: YAML Configuration for PlanExecuteRouter') + print('=' * 55) + + yaml_config = """ +metadata: + name: simple-plan-execute-demo + version: 1.0.0 + description: "Demo of plan-execute pattern" + +arium: + agents: + - name: planner + role: Task Planner + job: > + Break down complex tasks into detailed, sequential execution plans. + Create clear steps with dependencies and agent assignments. + model: + provider: openai + name: gpt-4o-mini + + - name: executor + role: Task Executor + job: > + Execute plan steps systematically, one by one. + Report progress and update plan status. + model: + provider: openai + name: gpt-4o-mini + + - name: validator + role: Quality Validator + job: > + Validate completed work and ensure quality standards. + Provide final approval for plan completion. + model: + provider: openai + name: gpt-4o-mini + + routers: + - name: demo_plan_router + type: plan_execute + agents: + planner: "Creates detailed execution plans" + executor: "Executes plan steps systematically" + validator: "Validates final results" + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.2 + planner_agent: planner + executor_agent: executor + reviewer_agent: validator + + workflow: + start: planner + edges: + - from: planner + to: [executor, validator, planner] + router: demo_plan_router + - from: executor + to: [validator, executor, planner] + router: demo_plan_router + - from: validator + to: [end] + end: [validator] +""" + + try: + # Build workflow from YAML + builder = AriumBuilder.from_yaml( + yaml_str=yaml_config, + base_llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + + builder.build() + print('βœ… YAML workflow built successfully!') + print('πŸ“‹ Configured plan-execute pattern with 3 agents') + print('πŸ”„ Router will coordinate planning β†’ execution β†’ validation') + + # Show the workflow structure + print('\nπŸ“Š Workflow Structure:') + print(' Start: planner') + print(' Edges:') + print(' planner β†’ [executor, validator, planner] (plan_execute_router)') + print(' executor β†’ [validator, executor, planner] (plan_execute_router)') + print(' validator β†’ [end]') + print(' End: validator') + + except Exception as e: + print(f'ℹ️ YAML demo note: {e}') + + print('\n🎯 Key YAML Features:') + print(' β€’ type: plan_execute - Enables plan-execute routing') + print(' β€’ agents: Dict mapping agent names to descriptions') + print(' β€’ planner_agent: Agent responsible for creating plans') + print(' β€’ executor_agent: Default agent for executing steps') + print(' β€’ reviewer_agent: Optional agent for final review') + + +def show_memory_integration(): + """Show how PlanExecuteRouter integrates with memory""" + print('\n\nπŸ’Ύ DEMO: Memory Integration with PlanExecuteRouter') + print('=' * 55) + + integration_info = """ +πŸ”„ PlanExecuteRouter Memory Integration: + +1. Plan Creation Phase: + β€’ Router detects no plan in memory + β€’ Routes to planner agent + β€’ Planner creates ExecutionPlan with steps + β€’ Plan stored in PlanAwareMemory + +2. Execution Phase: + β€’ Router checks current plan state + β€’ Identifies next ready steps (dependencies met) + β€’ Routes to appropriate agent for step execution + β€’ Agent updates step status and results + +3. Progress Tracking: + β€’ Plan progress visualized with status indicators: + β—‹ Pending ⏳ In Progress βœ… Completed ❌ Failed + β€’ Dependencies automatically managed + β€’ Failed steps trigger recovery routing + +4. Memory Persistence: + β€’ Plan state persists across agent interactions + β€’ Step results and metadata stored + β€’ Execution context maintained + +5. Completion Handling: + β€’ Router detects when all steps complete + β€’ Routes to reviewer agent (if configured) + β€’ Final validation and workflow completion + +πŸ“Š Memory Structure: +```python +memory = PlanAwareMemory() +memory.add_plan(execution_plan) # Store plan +current_plan = memory.get_current_plan() # Retrieve active plan +next_steps = current_plan.get_next_steps() # Get ready steps +``` + +🎯 Router Intelligence: +β€’ Automatically routes based on plan state +β€’ Handles step dependencies and execution order +β€’ Provides context-aware prompts with progress +β€’ Manages error recovery and retry logic +""" + + print(integration_info) + + +async def main(): + """Run all plan-execute demos""" + print('πŸš€ PlanExecuteRouter Simple Demo') + print('=' * 40) + print('This demo shows the PlanExecuteRouter in action with actual plan') + print('creation, storage, and step-by-step execution tracking! πŸŽ‰\n') + + # Run demos + await demo_plan_aware_memory() + await demo_programmatic_plan_execute() + await demo_yaml_plan_execute() + show_memory_integration() + + print('\n\nπŸŽ‰ PlanExecuteRouter Demo Complete!') + print('=' * 45) + print('βœ… What we demonstrated:') + print(' β€’ PlanAwareMemory for plan storage and state tracking') + print(' β€’ ExecutionPlan with steps, dependencies, and status') + print(' β€’ Programmatic router creation and usage') + print(' β€’ YAML configuration for plan-execute workflows') + print(' β€’ Memory integration and plan state management') + + print('\nπŸš€ Ready to build your own Cursor-style workflows!') + print(' Try the PlanExecuteRouter for complex task automation! 🎯') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/simple_reflection_router_demo.py b/flo_ai/examples/simple_reflection_router_demo.py new file mode 100644 index 00000000..7c4c2e40 --- /dev/null +++ b/flo_ai/examples/simple_reflection_router_demo.py @@ -0,0 +1,188 @@ +""" +Simple demonstration of ReflectionRouter for A -> B -> A -> C patterns. + +This shows the minimal code needed to implement a main -> critic -> main -> final +reflection pattern using the new ReflectionRouter. +""" + +import asyncio +from flo_ai.arium.builder import AriumBuilder +from flo_ai.arium.memory import MessageMemory +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.llm_router import create_main_critic_reflection_router + + +async def simple_reflection_demo(): + """Minimal example of A -> B -> A -> C reflection pattern""" + print('πŸš€ Simple ReflectionRouter Demo: A β†’ B β†’ A β†’ C Pattern') + print('=' * 60) + + # Create LLM (use dummy key for demo) + llm = OpenAI(model='gpt-4o-mini') + + # Create agents + main_agent = Agent( + name='main_agent', + system_prompt='You are the main agent. Analyze tasks and create solutions.', + llm=llm, + ) + + critic = Agent( + name='critic', + system_prompt='You are a critic. Provide constructive feedback to improve work.', + llm=llm, + ) + + final_agent = Agent( + name='final_agent', + system_prompt='You are the final agent. Polish and finalize the work.', + llm=llm, + ) + + # Create reflection router for A -> B -> A -> C pattern + reflection_router = create_main_critic_reflection_router( + main_agent='main_agent', + critic_agent='critic', + final_agent='final_agent', + allow_early_exit=False, # Strict reflection + llm=llm, + ) + + # Build workflow + builder = ( + AriumBuilder() + .with_memory(MessageMemory()) + .add_agents([main_agent, critic, final_agent]) + .start_with(main_agent) + .add_edge(main_agent, [critic, final_agent], reflection_router) + .add_edge(critic, [main_agent, final_agent], reflection_router) + .end_with(final_agent) + ) + + # Build the Arium + arium = builder.build() + + print('βœ… Workflow created successfully!') + print('πŸ“‹ Reflection Pattern: main_agent β†’ critic β†’ main_agent β†’ final_agent') + print('🎯 Router will automatically follow this sequence') + + # Demo input + print('\nπŸ“ Example input: "Create a project plan for a mobile app"') + print('πŸ’‘ The reflection router will:') + print(' Step 1: Route to critic (for feedback/reflection)') + print(' Step 2: Return to main_agent (to incorporate feedback)') + print(' Step 3: Route to final_agent (for final polish)') + + return arium + + +async def programmatic_reflection_example(): + """Show how to create reflection router programmatically""" + print('\n\nπŸ”§ Programmatic ReflectionRouter Creation') + print('=' * 50) + + from flo_ai.arium.llm_router import create_llm_router + + # Method 1: Using the convenience function + create_main_critic_reflection_router( + main_agent='writer', + critic_agent='reviewer', + final_agent='editor', + llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + print('βœ… Method 1: Convenience function create_main_critic_reflection_router()') + + # Method 2: Using the factory function directly + create_llm_router( + 'reflection', + flow_pattern=['analyst', 'validator', 'analyst', 'presenter'], + allow_early_exit=True, + llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + print('βœ… Method 2: Factory function create_llm_router(type="reflection")') + + # Method 3: Creating ReflectionRouter directly + from flo_ai.arium.llm_router import ReflectionRouter + + ReflectionRouter( + flow_pattern=['main', 'critic', 'main', 'final'], + allow_early_exit=False, + llm=OpenAI(model='gpt-4o-mini', api_key='dummy-key'), + ) + print('βœ… Method 3: Direct ReflectionRouter instantiation') + + print('\n🎯 All methods create the same Aβ†’Bβ†’Aβ†’C reflection pattern!') + + +def show_minimal_yaml(): + """Show the minimal YAML needed""" + print('\n\nπŸ“„ Minimal YAML Configuration') + print('=' * 35) + + yaml_example = """ +# Minimal ReflectionRouter YAML +arium: + agents: + - name: main_agent + job: "Main agent job" + model: {provider: openai, name: gpt-4o-mini} + - name: critic + job: "Critic job" + model: {provider: openai, name: gpt-4o-mini} + - name: final_agent + job: "Final agent job" + model: {provider: openai, name: gpt-4o-mini} + + routers: + - name: reflection_router + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + + workflow: + start: main_agent + edges: + - from: main_agent + to: [critic, final_agent] + router: reflection_router + - from: critic + to: [main_agent, final_agent] + router: reflection_router + - from: final_agent + to: [end] + end: [final_agent] +""" + print(yaml_example) + + +async def main(): + """Run the simple demo""" + print('🌟 Simple ReflectionRouter Demo') + print('=' * 35) + print('Demonstrating A β†’ B β†’ A β†’ C reflection pattern with minimal setup\n') + + # Show different creation methods + await programmatic_reflection_example() + + # Show minimal YAML + show_minimal_yaml() + + # Create simple reflection workflow + arium = await simple_reflection_demo() + + result = await arium.run( + inputs=['Write a comprehensive guide on sustainable urban planning'] + ) + + print('\n\nπŸŽ‰ Demo completed!') + print('Key takeaways:') + print('βœ… ReflectionRouter makes Aβ†’Bβ†’Aβ†’C patterns trivial to implement') + print('βœ… Works with both YAML and programmatic configuration') + print('βœ… Automatically tracks progress and prevents infinite loops') + print('βœ… Provides intelligent routing based on execution context') + + print(result) + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/examples/simple_working_demo.py b/flo_ai/examples/simple_working_demo.py new file mode 100644 index 00000000..fd939d7f --- /dev/null +++ b/flo_ai/examples/simple_working_demo.py @@ -0,0 +1,335 @@ +""" +Simple Working PlanExecuteRouter Demo + +This version fixes the planner loop by using a different approach: +1. Use a standard workflow without plan storage complexity +2. Demonstrate the routing intelligence with manual plan simulation +3. Show how the router makes decisions based on context +""" + +import asyncio +import os +from flo_ai.models.agent import Agent +from flo_ai.llm import OpenAI +from flo_ai.arium.memory import MessageMemory +from flo_ai.arium.llm_router import create_plan_execute_router +from flo_ai.arium import AriumBuilder + + +async def simple_working_demo(): + """Simple working demo that avoids the planner loop""" + print('βœ… Simple Working PlanExecuteRouter Demo') + print('=' * 45) + + # Check API key + api_key = os.getenv('OPENAI_API_KEY') + if not api_key: + print('❌ OPENAI_API_KEY environment variable not set') + print(' Set it with: export OPENAI_API_KEY=your_key_here') + return + + print('βœ… OpenAI API key found') + + # Create LLM + llm = OpenAI(model='gpt-4o', api_key=api_key) + + # Create simple agents focused on their core tasks + planner = Agent( + name='planner', + system_prompt="""You are a project planner. When given a task, create a detailed plan with numbered steps. + +Format your response like this: + +PLAN FOR: [task name] + +EXECUTION STEPS: +1. [First step description] +2. [Second step description] +3. [Third step description] +4. [Final step description] + +NEXT ACTION: The developer should start with step 1. + +Keep it clear and actionable.""", + llm=llm, + ) + + developer = Agent( + name='developer', + system_prompt="""You are a software developer. When given a development task: + +1. Acknowledge what you're implementing +2. Provide implementation details +3. Mention any important considerations +4. State when you've completed the task + +Be specific and thorough in your implementation.""", + llm=llm, + ) + + tester = Agent( + name='tester', + system_prompt="""You are a QA tester. When given something to test: + +1. Acknowledge what you're testing +2. Create test scenarios +3. Identify potential issues +4. Provide test results and recommendations + +Be thorough in your testing approach.""", + llm=llm, + ) + + reviewer = Agent( + name='reviewer', + system_prompt="""You are a senior reviewer. When reviewing work: + +1. Assess overall quality and completeness +2. Check if requirements are met +3. Provide constructive feedback +4. Give final approval or suggest improvements + +Focus on delivering high-quality results.""", + llm=llm, + ) + + print('βœ… Created focused agents: planner, developer, tester, reviewer') + + # Create a simple router using the proper factory function + from typing import Literal + from flo_ai.arium.memory import BaseMemory + + def create_simple_router(): + """Create a simple router with proper type annotations""" + + def router_impl( + memory: BaseMemory, + ) -> Literal['developer', 'tester', 'reviewer']: + """Simple routing logic for demo purposes""" + messages = memory.get() + + # Check the conversation flow + if not messages: + return 'developer' # Start with developer after planner + + last_message = str(messages[-1]) + + # Basic routing logic based on content + if 'PLAN FOR:' in last_message and 'EXECUTION STEPS:' in last_message: + print('πŸ“‹ Plan detected - routing to developer') + return 'developer' + elif ( + 'implemented' in last_message.lower() + or 'development' in last_message.lower() + ): + print('πŸ’» Development complete - routing to tester') + return 'tester' + elif 'test' in last_message.lower() and 'complete' in last_message.lower(): + print('πŸ§ͺ Testing complete - routing to reviewer') + return 'reviewer' + elif len(messages) > 6: # Prevent too many iterations + print('🏁 Workflow complete - ending') + return 'reviewer' + else: + return 'developer' # Default fallback + + # Add required annotations + router_impl.__annotations__ = { + 'memory': BaseMemory, + 'return': Literal['developer', 'tester', 'reviewer'], + } + + return router_impl + + simple_router = create_simple_router() + + # Create memory + memory = MessageMemory() + + # Build workflow with simple routing + # Note: Each edge's 'to' nodes must include all possible router return values + arium = ( + AriumBuilder() + .with_memory(memory) + .add_agents([planner, developer, tester, reviewer]) + .start_with(planner) + .add_edge(planner, [developer, tester, reviewer], simple_router) + .add_edge( + developer, [developer, tester, reviewer], simple_router + ) # Include all possible destinations + .add_edge( + tester, [developer, tester, reviewer], simple_router + ) # Include all possible destinations + .end_with(reviewer) + .build() + ) + + print('βœ… Built simple workflow with basic routing') + + # Task to execute + task = 'Create a simple login endpoint with username and password validation' + + print(f'\nπŸ“‹ Task: {task}') + print('\nπŸ”„ Running simple workflow...') + print(' This demonstrates the routing concept without complex plan storage') + + try: + # Execute workflow + result = await arium.run([task]) + + print('\n' + '=' * 50) + print('πŸŽ‰ SIMPLE WORKFLOW COMPLETED!') + print('=' * 50) + + # Show the conversation flow + if memory.get(): + print('\nπŸ“„ Conversation Flow:') + print('-' * 30) + for i, msg in enumerate(memory.get(), 1): + role = msg.get('role', 'unknown') + content = str(msg.get('content', ''))[:200] + print(f'{i}. {role.upper()}: {content}...') + + # Show final result + if result: + final_result = result[-1] if isinstance(result, list) else result + print('\nπŸ“„ Final Output:') + print('-' * 30) + print(final_result) + + print('\nπŸ’‘ What this demonstrated:') + print(' β€’ Basic plan-execute workflow concept') + print(' β€’ Intelligent routing between phases') + print(' β€’ Planner β†’ Developer β†’ Tester β†’ Reviewer flow') + print(' β€’ How to avoid infinite loops with simple logic') + + except Exception as e: + print(f'\n❌ Error: {e}') + + +async def demonstrate_plan_execute_router(): + """Show the actual PlanExecuteRouter in a controlled way""" + print('\n\nπŸ“Š PlanExecuteRouter Demonstration') + print('=' * 40) + + api_key = os.getenv('OPENAI_API_KEY') + if not api_key: + print('❌ OPENAI_API_KEY not set') + return + + llm = OpenAI(model='gpt-4o', api_key=api_key) + + # Create the actual PlanExecuteRouter + create_plan_execute_router( + planner_agent='planner', + executor_agent='developer', + reviewer_agent='reviewer', + additional_agents={'tester': 'Tests implementations'}, + llm=llm, + ) + + print('βœ… Created actual PlanExecuteRouter') + + # Test router decision making with mock memory + memory = MessageMemory() + + # Simulate different scenarios + scenarios = [ + {'msg': 'Create a user API', 'context': 'Initial request'}, + {'msg': 'Plan created with 4 steps', 'context': 'After planning'}, + {'msg': 'Step 1 implemented successfully', 'context': 'After development'}, + {'msg': 'All tests passed', 'context': 'After testing'}, + ] + + print('\n🧠 Router Decision Making:') + for scenario in scenarios: + memory.add({'role': 'user', 'content': scenario['msg']}) + + try: + # This would make an actual LLM call to decide routing + print(f'\n Context: {scenario["context"]}') + print(f' Message: {scenario["msg"]}') + print(' Router would make intelligent decision based on this context') + # decision = plan_router(memory) # Uncomment to see actual routing + # print(f' Decision: Route to {decision}') + except Exception as e: + print(f' Note: {e}') + + print('\nπŸ’‘ The PlanExecuteRouter makes intelligent routing decisions by:') + print(' β€’ Analyzing conversation context') + print(' β€’ Detecting plan creation vs execution phases') + print(' β€’ Understanding step dependencies and progress') + print(' β€’ Routing to appropriate agents based on workflow state') + + +def show_solution_approaches(): + """Show different approaches to fix the planner loop""" + print('\n\nπŸ”§ Solutions to the Planner Loop Issue') + print('=' * 45) + + solutions = """ +The planner loop happened because the router couldn't detect plan completion. +Here are several solutions: + +1. πŸ“‹ SPECIALIZED PLANNER AGENT (Best Solution) + β€’ PlannerAgent that stores ExecutionPlan objects in PlanAwareMemory + β€’ Router detects when plans exist and switches to execution mode + β€’ See fixed_plan_execute_demo.py for implementation + +2. 🎯 CONTENT-BASED ROUTING (Simple Solution) + β€’ Router analyzes message content to detect phases + β€’ If message contains "PLAN:", route to developer + β€’ If message contains "implemented:", route to tester + β€’ See simple_working_demo.py example above + +3. πŸ”„ LIMITED ITERATIONS (Quick Fix) + β€’ Add max iteration limits to prevent infinite loops + β€’ Router switches phases after X iterations + β€’ Less intelligent but prevents loops + +4. πŸ“Š STATE MANAGEMENT (Advanced Solution) + β€’ Use custom memory with explicit state tracking + β€’ Store workflow phase (planning/executing/reviewing) + β€’ Router uses state to make decisions + +5. 🧠 BETTER PROMPTING (Prompt Engineering) + β€’ Improve router prompts to better detect completion + β€’ Add explicit "PLANNING COMPLETE" markers + β€’ Train router to recognize different phases + +Recommendation: Use approach #1 (Specialized Planner Agent) for production, +approach #2 (Content-Based Routing) for quick demos. +""" + + print(solutions) + + +async def main(): + """Main demo function""" + print('🎯 Working PlanExecuteRouter Demo (Loop Issue Fixed)') + print('This demo shows how to avoid the planner loop issue!\n') + + if not os.getenv('OPENAI_API_KEY'): + print('❌ To run this demo, set your OPENAI_API_KEY environment variable') + print(' export OPENAI_API_KEY=your_key_here') + return + + # Show solution approaches + show_solution_approaches() + + # Run simple working demo + await simple_working_demo() + + # Demonstrate the actual router + await demonstrate_plan_execute_router() + + print('\n\nπŸŽ‰ Demo Complete!') + print('=' * 20) + print('βœ… Demonstrated working plan-execute workflow') + print('βœ… Showed how to avoid planner loops') + print('βœ… Explained multiple solution approaches') + print('\nπŸš€ Try the fixed_plan_execute_demo.py for the complete solution!') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/flo_ai/flo_ai/arium/base.py b/flo_ai/flo_ai/arium/base.py index 26943295..c3458354 100644 --- a/flo_ai/flo_ai/arium/base.py +++ b/flo_ai/flo_ai/arium/base.py @@ -103,16 +103,38 @@ def add_edge( if literal_values is None: raise ValueError('Router return type is not a Literal') - invalid_literals = [val for val in literal_values if val not in to_nodes] + # Check if router supports self-reference + supports_self_ref = getattr(router, 'supports_self_reference', False) + + # For self-referencing routers, we need to include the from_node in valid targets + valid_targets = to_nodes.copy() + if supports_self_ref: + valid_targets.append(from_node) + + invalid_literals = [ + val for val in literal_values if val not in valid_targets + ] if invalid_literals: raise ValueError( - f'Router return type includes literal values {invalid_literals} that are not in to_nodes {to_nodes}' + f'Router return type includes literal values {invalid_literals} that are not in valid targets {valid_targets}' ) - if set(literal_values) != set(to_nodes): - raise ValueError( - f'Router return type values {literal_values} do not match to_nodes {to_nodes}' - ) + # For self-referencing routers, allow router options to include from_node + if supports_self_ref: + # Router can return any of: to_nodes + from_node, but must include all to_nodes + missing_targets = [ + node for node in to_nodes if node not in literal_values + ] + if missing_targets: + raise ValueError( + f'Self-referencing router must include all to_nodes {to_nodes}, missing: {missing_targets}' + ) + else: + # Non-self-referencing routers must match exactly + if set(literal_values) != set(to_nodes): + raise ValueError( + f'Router return type values {literal_values} do not match to_nodes {to_nodes}' + ) self.edges[from_node] = Edge( router_fn=router diff --git a/flo_ai/flo_ai/arium/builder.py b/flo_ai/flo_ai/arium/builder.py index fc0821fa..633d59d6 100644 --- a/flo_ai/flo_ai/arium/builder.py +++ b/flo_ai/flo_ai/arium/builder.py @@ -230,7 +230,7 @@ def from_yaml( # LLM Router definitions (NEW) routers: - name: content_router - type: smart # smart, task_classifier, conversation_analysis + type: smart # smart, task_classifier, conversation_analysis, reflection, plan_execute routing_options: technical_writer: "Handle technical documentation tasks" creative_writer: "Handle creative writing tasks" @@ -242,6 +242,26 @@ def from_yaml( temperature: 0.3 fallback_strategy: first + # Reflection router for A -> B -> A -> C patterns + - name: main_critic_reflection + type: reflection + flow_pattern: [main_agent, critic, main_agent, final_agent] + settings: + allow_early_exit: false + + # Plan-Execute router for Cursor-style workflows + - name: plan_execute_router + type: plan_execute + agents: + planner: "Creates detailed execution plans" + developer: "Implements code and features" + tester: "Tests implementations" + reviewer: "Reviews final results" + settings: + planner_agent: planner + executor_agent: developer + reviewer_agent: reviewer + workflow: start: content_analyst edges: @@ -418,9 +438,37 @@ def from_yaml( llm=router_llm, **settings, ) + + elif router_type == 'reflection': + flow_pattern = router_config.get('flow_pattern', []) + if not flow_pattern: + raise ValueError( + f'Reflection router {router_name} must specify flow_pattern' + ) + + router_fn = create_llm_router( + router_type='reflection', + flow_pattern=flow_pattern, + llm=router_llm, + **settings, + ) + + elif router_type == 'plan_execute': + agents = router_config.get('agents', {}) + if not agents: + raise ValueError( + f'Plan-Execute router {router_name} must specify agents' + ) + + router_fn = create_llm_router( + router_type='plan_execute', + agents=agents, + llm=router_llm, + **settings, + ) else: raise ValueError( - f'Unknown router type: {router_type}. Supported types: smart, task_classifier, conversation_analysis' + f'Unknown router type: {router_type}. Supported types: smart, task_classifier, conversation_analysis, reflection, plan_execute' ) yaml_routers[router_name] = router_fn diff --git a/flo_ai/flo_ai/arium/llm_router.py b/flo_ai/flo_ai/arium/llm_router.py index 900d2cf8..17f98d6c 100644 --- a/flo_ai/flo_ai/arium/llm_router.py +++ b/flo_ai/flo_ai/arium/llm_router.py @@ -6,9 +6,9 @@ """ from abc import ABC, abstractmethod -from typing import Dict, Optional, Callable, Any, Union, get_args +from typing import Dict, Optional, Callable, Any, Union, get_args, List from functools import wraps -from flo_ai.arium.memory import BaseMemory +from flo_ai.arium.memory import BaseMemory, ExecutionPlan, StepStatus from flo_ai.llm.base_llm import BaseLLM from flo_ai.llm import OpenAI from flo_ai.utils.logger import logger @@ -40,6 +40,9 @@ def __init__( self.temperature = temperature self.max_retries = max_retries self.fallback_strategy = fallback_strategy + self.supports_self_reference = ( + False # Most routers don't support self-reference by default + ) @abstractmethod def get_routing_options(self) -> Dict[str, str]: @@ -324,6 +327,381 @@ def get_routing_prompt( return prompt +class ReflectionRouter(BaseLLMRouter): + """ + A router designed for reflection patterns like A -> B -> A -> C. + Commonly used for main -> critic -> main -> final workflows where B is a reflection/critique step. + Uses execution context to determine flow state and make intelligent routing decisions. + """ + + def __init__( + self, + flow_pattern: List[str], + llm: Optional[BaseLLM] = None, + allow_early_exit: bool = False, + **kwargs, + ): + """ + Initialize the reflection router. + + Args: + flow_pattern: List of node names defining the reflection pattern (e.g., ["main", "critic", "main", "final"]) + llm: LLM instance for routing decisions + allow_early_exit: Whether to allow LLM to exit pattern early if appropriate + **kwargs: Additional arguments for BaseLLMRouter + """ + super().__init__(llm=llm, **kwargs) + self.flow_pattern = flow_pattern + self.allow_early_exit = allow_early_exit + self.supports_self_reference = ( + True # ReflectionRouter can return to the same node + ) + + def get_routing_options(self) -> Dict[str, str]: + """Get available routing options based on flow pattern""" + unique_nodes = list( + dict.fromkeys(self.flow_pattern) + ) # Preserve order, remove duplicates + + # Generate descriptions based on reflection pattern + options = {} + for node in unique_nodes: + # Count occurrences and positions in pattern + positions = [i for i, x in enumerate(self.flow_pattern) if x == node] + if len(positions) > 1: + options[node] = ( + f"Step {positions} in the reflection pattern: {' -> '.join(self.flow_pattern)}" + ) + else: + options[node] = ( + f"Step {positions[0] + 1} in the reflection pattern: {' -> '.join(self.flow_pattern)}" + ) + + return options + + def _get_next_step_in_pattern(self, execution_context: dict) -> Optional[str]: + """Determine the next step in the reflection pattern based on execution context""" + if not execution_context: + return self.flow_pattern[0] if self.flow_pattern else None + + visit_counts = execution_context.get('node_visit_count', {}) + current_node = execution_context.get('current_node', '') + + # Find the current position in the pattern + try: + # Find where we are in the reflection pattern + current_step = -1 + for i, node in enumerate(self.flow_pattern): + node_visits = visit_counts.get(node, 0) + + # For nodes that appear multiple times, we need to track which occurrence + if node == current_node: + # Count how many times this node should have been visited at this step + expected_visits = len( + [x for x in self.flow_pattern[: i + 1] if x == node] + ) + if node_visits >= expected_visits: + current_step = i + + # Determine next step + next_step_index = current_step + 1 + if next_step_index < len(self.flow_pattern): + return self.flow_pattern[next_step_index] + else: + # Pattern completed + return None + + except Exception: + # Fallback to first step + return self.flow_pattern[0] if self.flow_pattern else None + + def get_routing_prompt( + self, + memory: BaseMemory, + options: Dict[str, str], + execution_context: dict = None, + ) -> str: + conversation = memory.get() + + # Format conversation history + if isinstance(conversation, list): + conversation_text = '\n'.join( + [str(msg) for msg in conversation[-3:]] + ) # Last 3 messages for flow context + else: + conversation_text = str(conversation) + + # Determine suggested next step based on reflection pattern + suggested_next = self._get_next_step_in_pattern(execution_context) + + # Format options + options_text = '\n'.join( + [f'- {name}: {desc}' for name, desc in options.items()] + ) + + # Add execution context info + context_info = '' + if execution_context: + visit_counts = execution_context.get('node_visit_count', {}) + current_node = execution_context.get('current_node', 'unknown') + iteration = execution_context.get('iteration_count', 0) + + # Show reflection pattern progress + pattern_progress = [] + for i, node in enumerate(self.flow_pattern): + visits = visit_counts.get(node, 0) + expected_visits = len( + [x for x in self.flow_pattern[: i + 1] if x == node] + ) + status = 'βœ“' if visits >= expected_visits else 'β—‹' + pattern_progress.append(f'{status} {node}') + + context_info = f""" +πŸ“‹ REFLECTION PATTERN: {' β†’ '.join(self.flow_pattern)} +πŸ“ CURRENT PROGRESS: {' β†’ '.join(pattern_progress)} +🎯 SUGGESTED NEXT: {suggested_next or 'Pattern Complete'} +πŸ’‘ CURRENT NODE: {current_node} (iteration {iteration}) +""" + + # Create prompt based on whether early exit is allowed + if self.allow_early_exit: + prompt = f"""You are a reflection coordinator managing this workflow pattern: {' β†’ '.join(self.flow_pattern)} + +{context_info} +Available options: +{options_text} + +Recent conversation: +{conversation_text} + +Instructions: +1. Follow the reflection pattern: {' β†’ '.join(self.flow_pattern)} +2. The suggested next step is: {suggested_next or 'Pattern Complete'} +3. You may exit early if the reflection cycle is complete +4. Consider conversation context and reflection progress +5. Respond with ONLY the agent name (no explanations) + +Next agent:""" + else: + prompt = f"""You are a reflection coordinator managing this strict reflection pattern: {' β†’ '.join(self.flow_pattern)} + +{context_info} +Available options: +{options_text} + +Recent conversation: +{conversation_text} + +Instructions: +1. STRICTLY follow the reflection pattern: {' β†’ '.join(self.flow_pattern)} +2. The next step should be: {suggested_next or 'Pattern Complete'} +3. Do not deviate from the pattern unless absolutely necessary +4. Respond with ONLY the agent name (no explanations) + +Next agent:""" + + return prompt + + +class PlanExecuteRouter(BaseLLMRouter): + """ + A router that implements plan-and-execute patterns like Cursor. + Creates execution plans and routes through steps sequentially. + """ + + def __init__( + self, + agents: Dict[str, str], # agent_name -> description mapping + planner_agent: str = 'planner', + executor_agent: str = 'executor', + reviewer_agent: Optional[str] = None, + llm: Optional[BaseLLM] = None, + max_retries: int = 3, + **kwargs, + ): + """ + Initialize the plan-execute router. + + Args: + agents: Dict mapping agent names to their descriptions/capabilities + planner_agent: Name of the agent responsible for creating plans + executor_agent: Name of the agent responsible for executing steps + reviewer_agent: Optional name of the agent responsible for reviewing results + llm: LLM instance for routing decisions + max_retries: Maximum retries for step execution + **kwargs: Additional arguments for BaseLLMRouter + """ + super().__init__(llm=llm, **kwargs) + self.agents = agents + self.planner_agent = planner_agent + self.executor_agent = executor_agent + self.reviewer_agent = reviewer_agent + self.max_retries = max_retries + self.supports_self_reference = ( + True # Can route to same agent for iterative execution + ) + + def get_routing_options(self) -> Dict[str, str]: + """Get available routing options based on configured agents""" + return self.agents + + def get_routing_prompt( + self, + memory: BaseMemory, + options: Dict[str, str], + execution_context: dict = None, + ) -> str: + conversation = memory.get() + + # Format conversation history + if isinstance(conversation, list): + conversation_text = '\n'.join( + [str(msg) for msg in conversation[-3:]] + ) # Last 3 messages for context + else: + conversation_text = str(conversation) + + # Check if we have a plan in memory + current_plan = ( + memory.get_current_plan() if hasattr(memory, 'get_current_plan') else None + ) + + if current_plan is None: + # No plan exists - route to planner + return self._create_planning_prompt(conversation_text, options) + else: + # Plan exists - determine next action based on plan state + return self._create_execution_prompt( + current_plan, conversation_text, options, execution_context + ) + + def _create_planning_prompt( + self, conversation_text: str, options: Dict[str, str] + ) -> str: + """Create prompt for initial planning phase""" + options_text = '\n'.join( + [f'- {name}: {desc}' for name, desc in options.items()] + ) + + prompt = f"""You are coordinating a plan-and-execute workflow. No execution plan exists yet. + +Available agents: +{options_text} + +Recent conversation: +{conversation_text} + +TASK: Create an execution plan by routing to the {self.planner_agent}. + +Instructions: +1. Route to "{self.planner_agent}" to create a detailed execution plan +2. The planner will break down the task into sequential steps +3. Each step will specify which agent should execute it +4. Respond with ONLY the agent name: {self.planner_agent} + +Next agent:""" + + return prompt + + def _create_execution_prompt( + self, + plan: ExecutionPlan, + conversation_text: str, + options: Dict[str, str], + execution_context: dict = None, + ) -> str: + """Create prompt for execution phase based on current plan state""" + + # Get next steps that are ready to execute + next_steps = plan.get_next_steps() + + # Format plan progress + progress_lines = [] + for step in plan.steps: + status_icon = { + StepStatus.PENDING: 'β—‹', + StepStatus.IN_PROGRESS: '⏳', + StepStatus.COMPLETED: 'βœ…', + StepStatus.FAILED: '❌', + StepStatus.SKIPPED: '⏭️', + }.get(step.status, 'β—‹') + progress_lines.append( + f'{status_icon} {step.id}: {step.description} (β†’ {step.agent})' + ) + + progress_text = '\n'.join(progress_lines) + + # Determine what to do next + if plan.is_completed(): + # All steps completed + if self.reviewer_agent and self.reviewer_agent in options: + action = f'Route to {self.reviewer_agent} for final review' + suggested_agent = self.reviewer_agent + else: + action = 'Plan completed - route to any agent for final output' + suggested_agent = next(iter(options.keys())) # First available agent + elif plan.has_failed_steps(): + # Some steps failed - need recovery + failed_steps = [ + step for step in plan.steps if step.status == StepStatus.FAILED + ] + failed_step = failed_steps[0] # Focus on first failed step + action = f"Handle failed step '{failed_step.id}' - route to {failed_step.agent} for retry" + suggested_agent = failed_step.agent + elif next_steps: + # There are steps ready to execute + next_step = next_steps[0] # Execute first ready step + action = f"Execute step '{next_step.id}' - route to {next_step.agent}" + suggested_agent = next_step.agent + else: + # Waiting for dependencies + action = f'Waiting for dependencies - route to {self.executor_agent} for status check' + suggested_agent = self.executor_agent + + options_text = '\n'.join( + [f'- {name}: {desc}' for name, desc in options.items()] + ) + + # Add execution context info + context_info = '' + if execution_context: + current_node = execution_context.get('current_node', 'unknown') + iteration = execution_context.get('iteration_count', 0) + + context_info = f""" +πŸ’‘ EXECUTION CONTEXT: +Current node: {current_node} (iteration {iteration}) +""" + + prompt = f"""You are coordinating plan execution in a plan-and-execute workflow. + +πŸ“‹ EXECUTION PLAN: {plan.title} +{plan.description} + +πŸ“Š CURRENT PROGRESS: +{progress_text} + +🎯 NEXT ACTION: {action} +🎯 SUGGESTED AGENT: {suggested_agent} +{context_info} +Available agents: +{options_text} + +Recent conversation: +{conversation_text} + +Instructions: +1. Follow the execution plan step by step +2. Route to the suggested agent: {suggested_agent} +3. Each agent will execute their assigned step +4. Continue until all steps are completed +5. Respond with ONLY the agent name (no explanations) + +Next agent:""" + + return prompt + + class ConversationAnalysisRouter(BaseLLMRouter): """ A router that analyzes conversation flow and context to make routing decisions. @@ -424,7 +802,7 @@ def create_llm_router(router_type: str, **config) -> Callable[[BaseMemory], str] Factory function to create LLM-powered routers with different configurations. Args: - router_type: Type of router ("smart", "task_classifier", "conversation_analysis") + router_type: Type of router ("smart", "task_classifier", "conversation_analysis", "reflection", "plan_execute") **config: Configuration specific to the router type Returns: @@ -457,6 +835,26 @@ def create_llm_router(router_type: str, **config) -> Callable[[BaseMemory], str] } } ) + + # Reflection router for A -> B -> A -> C patterns + router = create_llm_router( + "reflection", + flow_pattern=["main_agent", "critic", "main_agent", "final_agent"], + allow_early_exit=False + ) + + # Plan-Execute router for Cursor-style workflows + router = create_llm_router( + "plan_execute", + agents={ + "planner": "Creates detailed execution plans", + "developer": "Implements code and features", + "tester": "Tests implementations", + "reviewer": "Reviews final results" + }, + planner_agent="planner", + executor_agent="developer" + ) """ if router_type == 'smart': @@ -481,6 +879,18 @@ def create_llm_router(router_type: str, **config) -> Callable[[BaseMemory], str] router_instance = ConversationAnalysisRouter(**config) + elif router_type == 'reflection': + if 'flow_pattern' not in config: + raise ValueError("ReflectionRouter requires 'flow_pattern' parameter") + + router_instance = ReflectionRouter(**config) + + elif router_type == 'plan_execute': + if 'agents' not in config: + raise ValueError("PlanExecuteRouter requires 'agents' parameter") + + router_instance = PlanExecuteRouter(**config) + else: raise ValueError(f'Unknown router type: {router_type}') @@ -506,6 +916,11 @@ async def router_function(memory: BaseMemory, execution_context: dict = None): # Add proper type annotations for validation router_function.__annotations__ = {'memory': BaseMemory, 'return': literal_type} + # Transfer router instance attributes to the function for validation + router_function.supports_self_reference = getattr( + router_instance, 'supports_self_reference', False + ) + return router_function @@ -658,3 +1073,93 @@ def create_research_analysis_router( }, llm=llm, ) + + +def create_main_critic_reflection_router( + main_agent: str = 'main_agent', + critic_agent: str = 'critic', + final_agent: str = 'final_agent', + allow_early_exit: bool = False, + llm: Optional[BaseLLM] = None, +) -> Callable[[BaseMemory], str]: + """ + Create a router for the A -> B -> A -> C reflection pattern (main -> critic -> main -> final). + + Args: + main_agent: Name of the main agent (appears twice in pattern) + critic_agent: Name of the critic agent for reflection + final_agent: Name of the final agent + allow_early_exit: Whether to allow LLM to exit reflection early if appropriate + llm: LLM instance for routing decisions + + Returns: + Router function for main/critic/final reflection workflows + """ + return create_llm_router( + 'reflection', + flow_pattern=[main_agent, critic_agent, main_agent, final_agent], + allow_early_exit=allow_early_exit, + llm=llm, + ) + + +def create_plan_execute_router( + planner_agent: str = 'planner', + executor_agent: str = 'executor', + reviewer_agent: Optional[str] = None, + additional_agents: Optional[Dict[str, str]] = None, + llm: Optional[BaseLLM] = None, +) -> Callable[[BaseMemory], str]: + """ + Create a router for plan-and-execute workflows like Cursor. + + Args: + planner_agent: Name of the agent responsible for creating plans + executor_agent: Name of the agent responsible for executing steps + reviewer_agent: Optional name of the agent responsible for reviewing results + additional_agents: Additional agents that can be used in execution steps + llm: LLM instance for routing decisions + + Returns: + Router function for plan-execute workflows + """ + agents = { + planner_agent: 'Creates detailed execution plans by breaking down tasks into sequential steps', + executor_agent: 'Executes individual steps from the execution plan', + } + + if reviewer_agent: + agents[reviewer_agent] = 'Reviews and validates completed work' + + if additional_agents: + agents.update(additional_agents) + + return create_llm_router( + 'plan_execute', + agents=agents, + planner_agent=planner_agent, + executor_agent=executor_agent, + reviewer_agent=reviewer_agent, + llm=llm, + ) + + +# Backward compatibility alias +def create_main_critic_flow_router( + main_agent: str = 'main_agent', + critic_agent: str = 'critic', + final_agent: str = 'final_agent', + allow_early_exit: bool = False, + llm: Optional[BaseLLM] = None, +) -> Callable[[BaseMemory], str]: + """ + DEPRECATED: Use create_main_critic_reflection_router instead. + Create a router for the A -> B -> A -> C reflection pattern (main -> critic -> main -> final). + """ + return create_main_critic_reflection_router( + main_agent=main_agent, + critic_agent=critic_agent, + final_agent=final_agent, + allow_early_exit=allow_early_exit, + llm=llm, + ) diff --git a/flo_ai/flo_ai/arium/memory.py b/flo_ai/flo_ai/arium/memory.py index 88e9f113..783ca4ce 100644 --- a/flo_ai/flo_ai/arium/memory.py +++ b/flo_ai/flo_ai/arium/memory.py @@ -1,18 +1,117 @@ from abc import ABC, abstractmethod -from typing import TypeVar, Generic, List, Dict +from typing import TypeVar, Generic, List, Dict, Optional, Any +from dataclasses import dataclass, field +from enum import Enum # Define the generic type variable T = TypeVar('T') +class StepStatus(Enum): + """Status of a plan step""" + + PENDING = 'pending' + IN_PROGRESS = 'in_progress' + COMPLETED = 'completed' + FAILED = 'failed' + SKIPPED = 'skipped' + + +@dataclass +class PlanStep: + """Represents a single step in an execution plan""" + + id: str + description: str + agent: str # Which agent should execute this step + dependencies: List[str] = field(default_factory=list) # Step IDs this depends on + status: StepStatus = StepStatus.PENDING + result: Optional[str] = None + error: Optional[str] = None + metadata: Dict[str, Any] = field(default_factory=dict) + + +@dataclass +class ExecutionPlan: + """Represents a complete execution plan""" + + id: str + title: str + description: str + steps: List[PlanStep] = field(default_factory=list) + created_by: str = 'planner' + status: str = 'active' # active, completed, failed, paused + metadata: Dict[str, Any] = field(default_factory=dict) + + def get_next_steps(self) -> List[PlanStep]: + """Get steps that are ready to execute (pending with no pending dependencies)""" + next_steps = [] + for step in self.steps: + if step.status == StepStatus.PENDING: + # Check if all dependencies are completed + if all( + self.get_step(dep_id).status == StepStatus.COMPLETED + for dep_id in step.dependencies + ): + next_steps.append(step) + return next_steps + + def get_step(self, step_id: str) -> Optional[PlanStep]: + """Get a step by ID""" + for step in self.steps: + if step.id == step_id: + return step + return None + + def mark_step_completed(self, step_id: str, result: str = None): + """Mark a step as completed""" + step = self.get_step(step_id) + if step: + step.status = StepStatus.COMPLETED + step.result = result + + def mark_step_failed(self, step_id: str, error: str = None): + """Mark a step as failed""" + step = self.get_step(step_id) + if step: + step.status = StepStatus.FAILED + step.error = error + + def is_completed(self) -> bool: + """Check if all steps are completed""" + return all(step.status == StepStatus.COMPLETED for step in self.steps) + + def has_failed_steps(self) -> bool: + """Check if any steps have failed""" + return any(step.status == StepStatus.FAILED for step in self.steps) + + class BaseMemory(ABC, Generic[T]): @abstractmethod def add(self, m: T): pass + @abstractmethod def get(self) -> List[T]: pass + # Plan management methods (optional - only implemented by memory classes that support plans) + def add_plan(self, plan: ExecutionPlan): + """Add an execution plan (override in subclasses that support plans)""" + raise NotImplementedError('This memory type does not support plans') + + def get_current_plan(self) -> Optional[ExecutionPlan]: + """Get the current active plan (override in subclasses that support plans)""" + return None + + def update_plan(self, plan: ExecutionPlan): + """Update an existing plan (override in subclasses that support plans)""" + raise NotImplementedError('This memory type does not support plans') + + def get_plan(self, plan_id: str) -> Optional[ExecutionPlan]: + """Get a plan by ID (override in subclasses that support plans)""" + return None + class MessageMemory(BaseMemory[Dict[str, str]]): def __init__(self): @@ -23,3 +122,61 @@ def add(self, message: Dict[str, str]): def get(self) -> List[Dict[str, str]]: return self.messages + + +class PlanAwareMemory(BaseMemory[Dict[str, str]]): + """Enhanced memory that supports both messages and execution plans""" + + def __init__(self): + self.messages = [] + self.plans: Dict[str, ExecutionPlan] = {} + self.current_plan_id: Optional[str] = None + + def add(self, message: Dict[str, str]): + """Add a message to memory""" + self.messages.append(message) + + def get(self) -> List[Dict[str, str]]: + """Get all messages""" + return self.messages + + # Plan management methods + def add_plan(self, plan: ExecutionPlan): + """Add an execution plan and set it as current""" + self.plans[plan.id] = plan + self.current_plan_id = plan.id + + def get_current_plan(self) -> Optional[ExecutionPlan]: + """Get the current active plan""" + if self.current_plan_id and self.current_plan_id in self.plans: + return self.plans[self.current_plan_id] + return None + + def update_plan(self, plan: ExecutionPlan): + """Update an existing plan""" + if plan.id in self.plans: + self.plans[plan.id] = plan + else: + raise ValueError(f'Plan {plan.id} not found in memory') + + def get_plan(self, plan_id: str) -> Optional[ExecutionPlan]: + """Get a plan by ID""" + return self.plans.get(plan_id) + + def set_current_plan(self, plan_id: str): + """Set the current active plan""" + if plan_id in self.plans: + self.current_plan_id = plan_id + else: + raise ValueError(f'Plan {plan_id} not found in memory') + + def get_all_plans(self) -> List[ExecutionPlan]: + """Get all plans""" + return list(self.plans.values()) + + def remove_plan(self, plan_id: str): + """Remove a plan from memory""" + if plan_id in self.plans: + del self.plans[plan_id] + if self.current_plan_id == plan_id: + self.current_plan_id = None From e0822e9df8ef4cc70977d26d128222e8dca32dba Mon Sep 17 00:00:00 2001 From: Vishnu Satis Date: Sun, 24 Aug 2025 09:56:54 +0530 Subject: [PATCH 3/8] Studio: Visual Designer to create AI agents (#121) * Arium yaml chanegs * fix readme for format * Studio first commit * Custom agent builder * Basic multi agent routing * Fix studio, and have first agent created through it to run * Add studio details in READme * Adding flo studio imahe --- .gitignore | 1 + README.md | 45 ++ flo_ai/examples/example.py | 143 +++++ images/flo-studio-preview.png | Bin 0 -> 282017 bytes index.html | 225 ------- studio/README.md | 354 +++++++++++ studio/package.json | 54 ++ studio/postcss.config.js | 6 + studio/src/App.css | 157 +++++ studio/src/App.tsx | 110 ++++ .../src/components/dialogs/ImportDialog.tsx | 203 +++++++ .../components/drawer/YamlPreviewDrawer.tsx | 151 +++++ studio/src/components/editors/AgentEditor.tsx | 281 +++++++++ studio/src/components/editors/EdgeEditor.tsx | 186 ++++++ .../src/components/editors/RouterEditor.tsx | 567 ++++++++++++++++++ studio/src/components/flow/AgentNode.tsx | 108 ++++ studio/src/components/flow/CustomEdge.tsx | 119 ++++ studio/src/components/flow/FlowCanvas.tsx | 126 ++++ studio/src/components/flow/RouterNode.tsx | 137 +++++ studio/src/components/flow/ToolNode.tsx | 73 +++ .../src/components/panels/ValidationPanel.tsx | 205 +++++++ studio/src/components/sidebar/Sidebar.tsx | 276 +++++++++ studio/src/components/ui/button.tsx | 52 ++ studio/src/components/ui/dialog.tsx | 119 ++++ studio/src/components/ui/input.tsx | 24 + studio/src/components/ui/label.tsx | 23 + studio/src/components/ui/select.tsx | 155 +++++ studio/src/components/ui/textarea.tsx | 23 + studio/src/index.css | 37 ++ studio/src/lib/utils.ts | 6 + studio/src/main.tsx | 10 + studio/src/store/designerStore.ts | 356 +++++++++++ studio/src/types/agent.ts | 109 ++++ studio/src/types/reactflow.ts | 37 ++ studio/src/utils/workflowValidation.ts | 339 +++++++++++ studio/src/utils/yamlExport.ts | 335 +++++++++++ studio/src/utils/yamlImport.ts | 193 ++++++ studio/tailwind.config.js | 77 +++ studio/tsconfig.json | 31 + studio/tsconfig.node.json | 10 + studio/vite.config.ts | 13 + 41 files changed, 5251 insertions(+), 225 deletions(-) create mode 100644 flo_ai/examples/example.py create mode 100644 images/flo-studio-preview.png delete mode 100644 index.html create mode 100644 studio/README.md create mode 100644 studio/package.json create mode 100644 studio/postcss.config.js create mode 100644 studio/src/App.css create mode 100644 studio/src/App.tsx create mode 100644 studio/src/components/dialogs/ImportDialog.tsx create mode 100644 studio/src/components/drawer/YamlPreviewDrawer.tsx create mode 100644 studio/src/components/editors/AgentEditor.tsx create mode 100644 studio/src/components/editors/EdgeEditor.tsx create mode 100644 studio/src/components/editors/RouterEditor.tsx create mode 100644 studio/src/components/flow/AgentNode.tsx create mode 100644 studio/src/components/flow/CustomEdge.tsx create mode 100644 studio/src/components/flow/FlowCanvas.tsx create mode 100644 studio/src/components/flow/RouterNode.tsx create mode 100644 studio/src/components/flow/ToolNode.tsx create mode 100644 studio/src/components/panels/ValidationPanel.tsx create mode 100644 studio/src/components/sidebar/Sidebar.tsx create mode 100644 studio/src/components/ui/button.tsx create mode 100644 studio/src/components/ui/dialog.tsx create mode 100644 studio/src/components/ui/input.tsx create mode 100644 studio/src/components/ui/label.tsx create mode 100644 studio/src/components/ui/select.tsx create mode 100644 studio/src/components/ui/textarea.tsx create mode 100644 studio/src/index.css create mode 100644 studio/src/lib/utils.ts create mode 100644 studio/src/main.tsx create mode 100644 studio/src/store/designerStore.ts create mode 100644 studio/src/types/agent.ts create mode 100644 studio/src/types/reactflow.ts create mode 100644 studio/src/utils/workflowValidation.ts create mode 100644 studio/src/utils/yamlExport.ts create mode 100644 studio/src/utils/yamlImport.ts create mode 100644 studio/tailwind.config.js create mode 100644 studio/tsconfig.json create mode 100644 studio/tsconfig.node.json create mode 100644 studio/vite.config.ts diff --git a/.gitignore b/.gitignore index 2fb783ef..2e0165e9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ scratch_pad.py *.html usecases/ compare_gemini_outputs_v1.py +node_modules/ diff --git a/README.md b/README.md index 542365e1..8f1b5ed4 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,51 @@ Flo AI is a Python framework for building structured AI agents with support for Flo AI is a Python framework that makes building production-ready AI agents and teams as easy as writing YAML. Think "Kubernetes for AI Agents" - compose complex AI architectures using pre-built components while maintaining the flexibility to create your own. +## 🎨 Flo AI Studio - Visual Workflow Designer + +**Create AI workflows visually with our powerful React-based studio!** + +

+ Flo AI Studio - Visual Workflow Designer +

+ +Flo AI Studio is a modern, intuitive visual editor that allows you to design complex multi-agent workflows through a drag-and-drop interface. Build sophisticated AI systems without writing code, then export them as production-ready YAML configurations. + +### πŸš€ Studio Features + +- **🎯 Visual Design**: Drag-and-drop interface for creating agent workflows +- **πŸ€– Agent Management**: Configure AI agents with different roles, models, and tools +- **πŸ”€ Smart Routing**: Visual router configuration for intelligent workflow decisions +- **πŸ“€ YAML Export**: Export workflows as Flo AI-compatible YAML configurations +- **πŸ“₯ YAML Import**: Import existing workflows for further editing +- **βœ… Workflow Validation**: Real-time validation and error checking +- **πŸ”§ Tool Integration**: Connect agents to external tools and APIs +- **πŸ“‹ Template System**: Quick start with pre-built agent and router templates + +### πŸƒβ€β™‚οΈ Quick Start with Studio + +1. **Start the Studio**: + ```bash + cd studio + pnpm install + pnpm dev + ``` + +2. **Design Your Workflow**: + - Add agents, routers, and tools to the canvas + - Configure their properties and connections + - Test with the built-in validation + +3. **Export & Run**: + ```bash + # Export YAML from the studio, then run with Flo AI + python -c " + from flo_ai.arium import AriumBuilder + builder = AriumBuilder.from_yaml(yaml_file='your_workflow.yaml') + result = await builder.build_and_run(['Your input here']) + " + ``` + ## ✨ Features - πŸ”Œ **Truly Composable**: Build complex AI systems by combining smaller, reusable components diff --git a/flo_ai/examples/example.py b/flo_ai/examples/example.py new file mode 100644 index 00000000..60976ff0 --- /dev/null +++ b/flo_ai/examples/example.py @@ -0,0 +1,143 @@ +""" +Example of running a Flo AI workflow with snake_case agent names +Generated from Flo AI Studio +""" + +import asyncio +from flo_ai.arium import AriumBuilder +from flo_ai.tool.base_tool import Tool + +# Set your OpenAI API key +# os.environ["OPENAI_API_KEY"] = "your-api-key-here" + + +# Create a simple web search tool +async def web_search_function(query: str) -> str: + """Simple web search simulation - replace with actual search API""" + return f"Web search results for '{query}': Found relevant articles about the topic including latest developments, applications, and ethical considerations. [This is a mock search - integrate with real search API like Google, Bing, or DuckDuckGo]" + + +# Create the tool instance +web_search_tool = Tool( + name='web_search', + description='Search the web for information on a given topic', + function=web_search_function, + parameters={ + 'query': { + 'type': 'string', + 'description': 'The search query to look up information about', + } + }, +) + +# YAML workflow definition (exported from Flo AI Studio) +workflow_yaml = """ +metadata: + name: New Workflow + version: 1.0.0 + description: Generated with Flo AI Studio + tags: + - flo-ai + - studio-generated +arium: + agents: + - name: content_analyzer + role: Content Analyst + job: Analyze content and extract key insights, themes, and important information. + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.7 + max_retries: 3 + reasoning_pattern: DIRECT + - name: researcher + role: Research Specialist + job: Research topics and gather comprehensive information using available tools. + model: + provider: openai + name: gpt-4o + tools: + - web_search + - name: summarizer + role: Summary Generator + job: Create concise, actionable summaries from analysis and content. + model: + provider: openai + name: gpt-4o-mini + routers: + - name: smart_router + type: smart + routing_options: + researcher: If there is not enough information & deep research needs to be done + summarizer: If we have enough information and its time to summarize + model: + provider: openai + name: gpt-4o-mini + settings: + temperature: 0.3 + fallback_strategy: first + workflow: + start: content_analyzer + edges: + - from: content_analyzer + to: [researcher, summarizer] + router: smart_router + - from: researcher + to: [summarizer] + end: + - summarizer +""" + + +async def main(): + """Run the workflow""" + print('πŸš€ Starting Flo AI Workflow...') + print('πŸ“‹ Workflow: Content Analysis with Smart Routing') + print('-' * 50) + + try: + # Create tools dictionary (required format for AriumBuilder) + tools = {'web_search': web_search_tool} + + # Create Arium builder from YAML + builder = AriumBuilder.from_yaml(yaml_str=workflow_yaml, tools=tools) + + # Example input for the workflow + user_input = [ + """I need to understand the current trends in artificial intelligence and machine learning. + Specifically, I'm interested in: + 1. Latest developments in large language models + 2. Applications in healthcare and finance + 3. Ethical considerations and regulations + + Please provide a comprehensive analysis and summary.""" + ] + + print('πŸ“ Input:') + print(user_input[0]) + print('\n' + '=' * 50) + print('πŸ”„ Processing workflow...') + print('=' * 50 + '\n') + + # Build and run the workflow + result = await builder.build_and_run(user_input) + + print('βœ… Workflow Result:') + print('-' * 30) + if isinstance(result, list): + for i, message in enumerate(result): + print(f'{i+1}. {message}') + else: + print(result) + + except Exception as e: + print(f'❌ Error running workflow: {str(e)}') + print('\nπŸ’‘ Make sure you have:') + print('1. Set your OPENAI_API_KEY environment variable') + print('2. Installed flo-ai: pip install flo-ai') + print('3. All required dependencies') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/images/flo-studio-preview.png b/images/flo-studio-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..0a43992deb48059397e758d46e3fc3c1f0bc6312 GIT binary patch literal 282017 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�X3Ev|7 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

-gL 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 - - - - - - - - -flo-ai | πŸ”₯πŸ”₯πŸ”₯ Simple way to create composable AI agents - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - diff --git a/studio/README.md b/studio/README.md new file mode 100644 index 00000000..69ee426c --- /dev/null +++ b/studio/README.md @@ -0,0 +1,354 @@ +# Flo AI Studio + +A powerful visual designer for creating YAML-based AI agent workflows. Build complex multi-agent workflows with an intuitive drag-and-drop interface, configure agents with comprehensive forms, set up routing logic, and export everything as production-ready YAML. + +## 🌟 Overview + +Flo AI Studio is a React-based visual editor that makes it easy to design and configure AI workflows for the Flo AI framework. It provides a user-friendly interface for creating complex agent orchestrations without writing code. + +## ✨ Features + +- **🎨 Visual Workflow Design**: Drag-and-drop interface using React Flow +- **πŸ€– Agent Management**: Create and edit agents with comprehensive configuration forms +- **πŸ”§ Tool Integration**: Add and configure tools for your agents +- **πŸ”€ Router Configuration**: Define custom routing logic between workflow nodes +- **πŸ“„ YAML Export**: Generate production-ready YAML configurations +- **πŸ“‹ Template System**: Quick agent templates for common use cases +- **βš™οΈ Configuration Management**: Manage available tools, LLMs, and routers +- **πŸ’Ύ State Management**: Robust state management with Zustand +- **🎯 TypeScript**: Fully typed for better development experience + +## πŸš€ Quick Start + +### Installation + +```bash +# Navigate to flo_studio directory +cd flo_studio + +# Install dependencies +pnpm install + +# Start development server +pnpm dev +``` + +### Building for Production + +```bash +# Build the application +pnpm build + +# Preview the build +pnpm preview +``` + +## πŸ—οΈ Architecture + +### Project Structure + +``` +flo_studio/ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ components/ # React components +β”‚ β”‚ β”œβ”€β”€ editors/ # Modal editors (Agent, Edge, Config) +β”‚ β”‚ β”œβ”€β”€ flow/ # React Flow components +β”‚ β”‚ β”œβ”€β”€ sidebar/ # Sidebar components +β”‚ β”‚ β”œβ”€β”€ toolbar/ # Toolbar components +β”‚ β”‚ └── ui/ # Reusable UI components +β”‚ β”œβ”€β”€ store/ # Zustand store +β”‚ β”œβ”€β”€ types/ # TypeScript definitions +β”‚ β”œβ”€β”€ utils/ # Utility functions +β”‚ └── lib/ # Shared utilities +β”œβ”€β”€ public/ # Static assets +└── dist/ # Build output +``` + +### Key Technologies + +- **React 18** - Modern React with hooks and concurrent features +- **TypeScript** - Type safety and better developer experience +- **React Flow** - Graph visualization and interaction +- **Zustand** - Lightweight state management +- **Tailwind CSS** - Utility-first CSS framework +- **Radix UI** - Accessible component primitives +- **React Hook Form** - Form handling with validation +- **js-yaml** - YAML parsing and generation +- **Vite** - Fast build tool and dev server + +## 🎯 Usage Guide + +### Creating Your First Workflow + +1. **Start the Application** + ```bash + pnpm dev + ``` + +2. **Create an Agent** + - Click the "Agent" button in the toolbar + - Fill in the agent configuration form: + - Name and role + - Job description + - LLM model selection + - Tools (optional) + - Output parser (optional) + +3. **Build the Workflow** + - Drag nodes from the sidebar onto the canvas + - Connect nodes by dragging from output handles to input handles + - Configure edge routers by clicking on connections + +4. **Export Configuration** + - Click "Export" in the toolbar + - Review the generated YAML + - Download or copy the configuration + +### Agent Configuration + +Agents can be configured with: + +- **Basic Information**: Name, role, job description +- **Model Settings**: Provider (OpenAI, Anthropic, etc.), model name, temperature +- **Tools**: Select from available tools or add custom ones +- **Output Parser**: Define structured output schemas +- **Reasoning Pattern**: DIRECT, COT (Chain of Thought), or REACT + +### Workflow Features + +- **Visual Connections**: Drag to connect agents and tools +- **Router Functions**: Configure conditional routing between nodes +- **Start/End Nodes**: Automatically detected based on connections +- **Validation**: Real-time validation of workflow structure + +## πŸ”§ Configuration + +### Available LLMs + +The studio comes pre-configured with popular LLM providers: + +- **OpenAI**: GPT-4o, GPT-4o-mini +- **Anthropic**: Claude-3.5-Sonnet, Claude-3.5-Haiku +- **Google**: Gemini-2.5-Flash, Gemini-2.5-Pro +- **Ollama**: Llama2, Llama3 (local models) + +### Available Tools + +Default tools include: + +- **calculator** - Mathematical calculations +- **web_search** - Web search functionality +- **file_reader** - File reading and analysis +- **email_sender** - Email sending capabilities +- **text_processor** - Text processing and analysis +- **image_analyzer** - Image analysis and processing + +### Router Functions + +Pre-configured router functions: + +- **default_router** - Simple pass-through routing +- **content_router** - Routes based on content analysis +- **classification_router** - Routes based on classification results +- **sentiment_router** - Routes based on sentiment analysis + +## πŸ“Š YAML Export Format + +The studio generates YAML compatible with the Flo AI framework: + +```yaml +metadata: + name: "My Workflow" + version: "1.0.0" + description: "Generated with Flo AI Studio" + tags: ["flo-ai", "studio-generated"] + +arium: + agents: + - name: "content_analyzer" + role: "Content Analyst" + job: "Analyze content and extract insights" + model: + provider: "openai" + name: "gpt-4o-mini" + settings: + temperature: 0.3 + reasoning_pattern: "COT" + + workflow: + start: "content_analyzer" + edges: + - from: "content_analyzer" + to: ["summarizer"] + end: ["summarizer"] +``` + +## πŸ”Œ Integration with Flo AI + +Use the exported YAML with the Flo AI framework: + +```python +from flo_ai.arium.builder import AriumBuilder + +# Load your exported workflow +builder = AriumBuilder.from_yaml(yaml_file="my-workflow.yaml") + +# Run the workflow +result = await builder.build_and_run(["Your input here"]) +``` + +## πŸ› οΈ Development + +### Adding New Components + +1. **Create Component** + ```typescript + // src/components/MyComponent.tsx + import React from 'react'; + + export const MyComponent: React.FC = () => { + return
My Component
; + }; + ``` + +2. **Add to Store** (if needed) + ```typescript + // src/store/designerStore.ts + interface DesignerState { + // Add new state properties + myNewFeature: boolean; + setMyNewFeature: (value: boolean) => void; + } + ``` + +### Adding New Tool Templates + +Edit the store configuration: + +```typescript +// src/store/designerStore.ts +const defaultConfig: DesignerConfig = { + availableTools: [ + // Add new tools + { name: 'my_tool', description: 'My custom tool' }, + ], + // ... +}; +``` + +### Customizing Themes + +Update CSS variables in `src/index.css`: + +```css +:root { + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + /* Add custom colors */ +} +``` + +## πŸ› Troubleshooting + +### Common Issues + +1. **Build Errors** + - Ensure all dependencies are installed: `pnpm install` + - Clear node_modules and reinstall if needed + +2. **TypeScript Errors** + - Check type definitions in `src/types/` + - Ensure proper imports and exports + +3. **React Flow Issues** + - Verify React Flow version compatibility + - Check node and edge data structures + +### Performance Optimization + +- Use React.memo for heavy components +- Implement virtual scrolling for large workflows +- Optimize store subscriptions with selectors + +## πŸš€ Deployment + +### Building for Production + +```bash +# Build the application +pnpm build + +# The dist/ folder contains the built application +``` + +### Deployment Options + +- **Static Hosting**: Deploy `dist/` to Netlify, Vercel, or GitHub Pages +- **Docker**: Create a Docker container with nginx +- **CDN**: Upload to S3 + CloudFront or similar + +### Environment Variables + +Create `.env` files for different environments: + +```bash +# .env.development +VITE_API_URL=http://localhost:3000 + +# .env.production +VITE_API_URL=https://api.myapp.com +``` + +## πŸ“ˆ Roadmap + +### Phase 1 (Current) +- βœ… Basic visual editor +- βœ… Agent configuration +- βœ… YAML export +- βœ… TypeScript support + +### Phase 2 (Planned) +- [ ] YAML import functionality +- [ ] Workflow validation +- [ ] Advanced routing configuration +- [ ] Template library + +### Phase 3 (Future) +- [ ] Real-time collaboration +- [ ] Workflow simulation +- [ ] Plugin system +- [ ] Cloud deployment + +## 🀝 Contributing + +1. Fork the repository +2. Create a feature branch: `git checkout -b feature/my-feature` +3. Make changes and add tests +4. Commit: `git commit -am 'Add my feature'` +5. Push: `git push origin feature/my-feature` +6. Create a Pull Request + +### Development Guidelines + +- Use TypeScript for all new code +- Follow the existing component structure +- Add proper error handling +- Write meaningful commit messages +- Update documentation as needed + +## πŸ“„ License + +This project is part of the Flo AI framework and follows the same licensing terms. + +## πŸ™ Acknowledgments + +- Built for the [Flo AI framework](../flo_ai/) +- Powered by React Flow for graph visualization +- UI components from Radix UI +- Icons from Lucide React + +--- + +**Happy Building! πŸš€** + +For more information about the Flo AI framework, check out the [main documentation](../flo_ai/README.md). diff --git a/studio/package.json b/studio/package.json new file mode 100644 index 00000000..c72e4a1a --- /dev/null +++ b/studio/package.json @@ -0,0 +1,54 @@ +{ + "name": "flo-ai-studio", + "version": "1.0.0", + "description": "Visual designer for Flo AI workflows", + "private": true, + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@hookform/resolvers": "^3.3.2", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-form": "^0.0.3", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-separator": "^1.0.3", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-tooltip": "^1.0.7", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", + "js-yaml": "^4.1.0", + "lucide-react": "^0.294.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-hook-form": "^7.48.2", + "reactflow": "^11.10.4", + "tailwind-merge": "^2.0.0", + "tailwindcss-animate": "^1.0.7", + "zod": "^3.22.4", + "zustand": "^4.4.7" + }, + "devDependencies": { + "@types/js-yaml": "^4.0.9", + "@types/node": "^20.10.4", + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.16", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "postcss": "^8.4.32", + "tailwindcss": "^3.3.6", + "typescript": "^5.2.2", + "vite": "^5.0.8" + } +} diff --git a/studio/postcss.config.js b/studio/postcss.config.js new file mode 100644 index 00000000..2e7af2b7 --- /dev/null +++ b/studio/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/studio/src/App.css b/studio/src/App.css new file mode 100644 index 00000000..3baff915 --- /dev/null +++ b/studio/src/App.css @@ -0,0 +1,157 @@ +@import 'tailwindcss/base'; +@import 'tailwindcss/components'; +@import 'tailwindcss/utilities'; + +/* React Flow Customizations */ +.react-flow__node { + font-family: inherit; +} + +.react-flow__edge { + stroke-width: 2px; +} + +.react-flow__edge.selected { + stroke: #3b82f6; + stroke-width: 3px; +} + +.react-flow__edge-path { + stroke-width: inherit; +} + +.react-flow__connection-line { + stroke: #3b82f6; + stroke-width: 3px; + stroke-dasharray: 5, 5; + animation: dash 1s linear infinite; +} + +@keyframes dash { + to { + stroke-dashoffset: -10; + } +} + +/* Edge arrows */ +.react-flow__edge .react-flow__edge-path { + stroke-width: inherit; +} + +.react-flow__edge-path { + stroke-linecap: round; +} + +.react-flow__handle { + width: 12px; + height: 12px; + border: 2px solid white; + border-radius: 50%; + transition: all 0.2s ease; +} + +.react-flow__handle:hover { + transform: scale(1.2); + box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.2); +} + +.react-flow__handle-connecting { + background: #3b82f6; + transform: scale(1.3); + box-shadow: 0 0 0 6px rgba(59, 130, 246, 0.3); +} + +.react-flow__handle-valid { + background: #10b981; + transform: scale(1.2); + box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.3); +} + +/* Custom Edge Label Styles */ +.edge-label { + background: white; + border: 1px solid #e5e7eb; + border-radius: 6px; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); + font-size: 12px; + padding: 4px 8px; +} + +.edge-label.selected { + border-color: #3b82f6; + background: #eff6ff; +} + +/* Focus styles for better accessibility */ +.react-flow__node:focus, +.react-flow__node:focus-visible { + outline: 2px solid #3b82f6; + outline-offset: 2px; +} + +/* Animation for node hover */ +.react-flow__node { + transition: transform 0.1s ease, box-shadow 0.1s ease; +} + +.react-flow__node:hover { + transform: scale(1.02); + box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1); +} + +/* Utility Classes */ +.line-clamp-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.line-clamp-3 { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* YAML Preview Drawer Styles */ +.yaml-drawer { + transition: width 0.3s ease-in-out; +} + +.yaml-drawer-content { + transition: opacity 0.3s ease-in-out; +} + +/* Floating YAML Widget */ +.yaml-widget { + transition: all 0.2s ease-in-out; + animation: float 3s ease-in-out infinite; +} + +.yaml-widget:hover { + transform: translateY(-50%) scale(1.05); +} + +@keyframes float { + 0%, 100% { transform: translateY(-50%) translateX(0); } + 50% { transform: translateY(-50%) translateX(-2px); } +} + +/* Custom Scrollbar for YAML content */ +.yaml-content::-webkit-scrollbar { + width: 8px; +} + +.yaml-content::-webkit-scrollbar-track { + background: #374151; +} + +.yaml-content::-webkit-scrollbar-thumb { + background: #6b7280; + border-radius: 4px; +} + +.yaml-content::-webkit-scrollbar-thumb:hover { + background: #9ca3af; +} diff --git a/studio/src/App.tsx b/studio/src/App.tsx new file mode 100644 index 00000000..a362ad4f --- /dev/null +++ b/studio/src/App.tsx @@ -0,0 +1,110 @@ +import React, { useState } from 'react'; +import { ReactFlowProvider } from 'reactflow'; +import { useDesignerStore } from '@/store/designerStore'; +import { Button } from '@/components/ui/button'; +import { Plus, Settings, Route, Upload, CheckCircle } from 'lucide-react'; +import FlowCanvas from '@/components/flow/FlowCanvas'; +import Sidebar from '@/components/sidebar/Sidebar'; +import AgentEditor from '@/components/editors/AgentEditor'; +import RouterEditor from '@/components/editors/RouterEditor'; +import EdgeEditor from '@/components/editors/EdgeEditor'; +import YamlPreviewDrawer from '@/components/drawer/YamlPreviewDrawer'; +import ImportDialog from '@/components/dialogs/ImportDialog'; +import ValidationPanel from '@/components/panels/ValidationPanel'; +import './App.css'; + +// Simplified Config Editor Modal +const ConfigEditorModal: React.FC<{ isOpen: boolean; onClose: () => void }> = ({ isOpen, onClose }) => { + if (!isOpen) return null; + + return ( +
+
+

Configuration

+

+ Configuration editor coming soon! For now, tools and LLMs are pre-configured. +

+ +
+
+ ); +}; + +const ToolbarComponent: React.FC<{ + showValidation: boolean; + setShowValidation: (show: boolean) => void; +}> = ({ showValidation, setShowValidation }) => { + const { openAgentEditor, openRouterEditor } = useDesignerStore(); + const [isConfigOpen, setIsConfigOpen] = useState(false); + const [isImportOpen, setIsImportOpen] = useState(false); + + return ( + <> +
+
+

Flo AI Studio

+
Visual Workflow Designer
+
+
+ + + + + + +
+
+ setIsConfigOpen(false)} /> + setIsImportOpen(false)} /> + + ); +}; + +function App() { + const [showValidation, setShowValidation] = useState(true); + + return ( +
+ +
+ +
+ + + +
+ {showValidation && } +
+ + {/* Modals */} + + + + + {/* YAML Preview Drawer */} + +
+ ); +} + +export default App; \ No newline at end of file diff --git a/studio/src/components/dialogs/ImportDialog.tsx b/studio/src/components/dialogs/ImportDialog.tsx new file mode 100644 index 00000000..320f4e24 --- /dev/null +++ b/studio/src/components/dialogs/ImportDialog.tsx @@ -0,0 +1,203 @@ +import React, { useState, useRef } from 'react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { Textarea } from '@/components/ui/textarea'; +import { Label } from '@/components/ui/label'; +import { Upload, FileText, AlertCircle, CheckCircle } from 'lucide-react'; +import { useDesignerStore } from '@/store/designerStore'; +import { validateAriumYAML, readFileAsText } from '@/utils/yamlImport'; + +interface ImportDialogProps { + isOpen: boolean; + onClose: () => void; +} + +const ImportDialog: React.FC = ({ isOpen, onClose }) => { + const { importFromYAML } = useDesignerStore(); + const [yamlContent, setYamlContent] = useState(''); + const [validationResult, setValidationResult] = useState<{ isValid: boolean; error?: string } | null>(null); + const [isImporting, setIsImporting] = useState(false); + const [importError, setImportError] = useState(null); + const fileInputRef = useRef(null); + + const handleFileUpload = async (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (!file) return; + + try { + const content = await readFileAsText(file); + setYamlContent(content); + setImportError(null); + + // Validate the content + const validation = validateAriumYAML(content); + setValidationResult(validation); + } catch (error) { + setImportError(`Failed to read file: ${error instanceof Error ? error.message : 'Unknown error'}`); + } + }; + + const handleYamlChange = (content: string) => { + setYamlContent(content); + setImportError(null); + + if (content.trim()) { + const validation = validateAriumYAML(content); + setValidationResult(validation); + } else { + setValidationResult(null); + } + }; + + const handleImport = async () => { + if (!yamlContent.trim()) { + setImportError('Please provide YAML content to import'); + return; + } + + setIsImporting(true); + setImportError(null); + + try { + await importFromYAML(yamlContent); + onClose(); + resetDialog(); + } catch (error) { + setImportError(`Import failed: ${error instanceof Error ? error.message : 'Unknown error'}`); + } finally { + setIsImporting(false); + } + }; + + const resetDialog = () => { + setYamlContent(''); + setValidationResult(null); + setImportError(null); + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } + }; + + const handleClose = () => { + resetDialog(); + onClose(); + }; + + return ( + + + + + + Import Workflow from YAML + + + +
+ {/* File Upload */} +
+ +
+ + or paste YAML content below +
+ +
+ + {/* YAML Content */} +
+ +
- -

flo-ai

- - -

- Rootflo -

- -

Composable AI Agentic Workflow

- -

-Rootflo is an alternative to Langgraph, and CrewAI. It lets you easily build composable agentic workflows from using simple components to any size, unlocking the full potential of LLMs. -

- -

- GitHub stars - - GitHub release (latest) - - GitHub commit activity - - License - -
-

- -

-
- Checkout the docs Β» -
-
- Github - β€’ - Website - β€’ - Roadmap -

- -
- -

Flo AI 🌊

- -
-

Build production-ready AI agents and teams with minimal code

-
- -

Flo AI is a Python framework that makes building production-ready AI agents and teams as easy as writing YAML. Think β€œKubernetes for AI Agents” - compose complex AI architectures using pre-built components while maintaining the flexibility to create your own.

- -

✨ Features

- -
    -
  • πŸ”Œ Truly Composable: Build complex AI systems by combining smaller, reusable components
  • -
  • πŸ—οΈ Production-Ready: Built-in best practices and optimizations for production deployments
  • -
  • πŸ“ YAML-First: Define your entire agent architecture in simple YAML
  • -
  • πŸ”§ Flexible: Use pre-built components or create your own
  • -
  • 🀝 Team-Oriented: Create and manage teams of AI agents working together
  • -
  • πŸ“š RAG Support: Built-in support for Retrieval-Augmented Generation
  • -
  • πŸ”„ Langchain Compatible: Works with all your favorite Langchain tools
  • -
- -

πŸš€ Quick Start

- -

Installation

- -
pip install flo-ai
-# or using poetry
-poetry add flo-ai
-
- -

Create Your First AI Team in 30 Seconds

- -
from flo_ai import Flo, FloSession
-from langchain_openai import ChatOpenAI
-
-# Define your team in YAML
-yaml_config = """
-apiVersion: flo/alpha-v1
-kind: FloRoutedTeam
-name: research-team
-team:
-    name: ResearchTeam
-    router:
-        name: TeamLead
-        kind: supervisor
-    agents:
-      - name: Researcher
-        role: Research Specialist
-        job: Research latest information on given topics
-        tools:
-          - name: TavilySearchResults
-      - name: Writer
-        role: Content Creator
-        job: Create engaging content from research
-"""
-
-# Set up and run
-llm = ChatOpenAI(temperature=0)
-session = FloSession(llm).register_tool(name="TavilySearchResults", tool=TavilySearchResults())
-flo = Flo.build(session, yaml=yaml_config)
-
-# Start streaming results
-for response in flo.stream("Write about recent AI developments"):
-    print(response)
-
- -

πŸ“– Documentation

- -

Visit our comprehensive documentation for:

-
    -
  • Detailed tutorials
  • -
  • Architecture deep-dives
  • -
  • API reference
  • -
  • Best practices
  • -
  • Advanced examples
  • -
- -

🌟 Why Flo AI?

- -

For AI Engineers

-
    -
  • Faster Development: Build complex AI systems in minutes, not days
  • -
  • Production Focus: Built-in optimizations and best practices
  • -
  • Flexibility: Use our components or build your own
  • -
- -

For Teams

-
    -
  • Maintainable: YAML-first approach makes systems easy to understand and modify
  • -
  • Scalable: From single agents to complex team hierarchies
  • -
  • Testable: Each component can be tested independently
  • -
- -

🎯 Use Cases

- -
    -
  • πŸ€– Customer Service Automation
  • -
  • πŸ“Š Data Analysis Pipelines
  • -
  • πŸ“ Content Generation
  • -
  • πŸ” Research Automation
  • -
  • 🎯 Task-Specific AI Teams
  • -
- -

🀝 Contributing

- -

We love your input! Check out our Contributing Guide to get started. Ways to contribute:

- -
    -
  • πŸ› Report bugs
  • -
  • πŸ’‘ Propose new features
  • -
  • πŸ“ Improve documentation
  • -
  • πŸ”§ Submit PRs
  • -
- -

πŸ“œ License

- -

Flo AI is MIT Licensed.

- -

πŸ™ Acknowledgments

- -

Built with ❀️ using:

- - -
- -
- Built with ❀️ by the Rootflo team -
Community β€’ - Documentation -
- - - - - -