AI-Native LangGraph Routing for Multi-Agent Coordination#12
Open
AI-Native LangGraph Routing for Multi-Agent Coordination#12
Conversation
- Add short-term memory support with ConversationMessage schema - Implement FileContent schema for base64 and signed URL file handling - Create agentic file processing workflow using UPEE pattern with retry logic - Add intelligent streaming completion detection to prevent response cutoffs - Fix schema compatibility between FileContent and FileContext formats - Implement debug API endpoints for troubleshooting file reception issues - Add comprehensive logging with structured request tracking - Create test utilities for file processing and response validation - Enhance OpenAI provider with smart completion detection and safety limits - Add database models, event bus, job scheduler, and plugin architecture 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Update debug API to support multipart form data for better file upload testing - Add max_tokens capping to prevent OpenAI API limits (16384 tokens) - Remove overly aggressive streaming completion detection - Add detailed execution parameter logging for debugging - Improve file processing agent with better error handling - Add comprehensive core agent specification documentation - Enhance plan phase with better token estimation and model selection - Update all LLM providers with consistent token limit handling - Clean up temporary documentation files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add detailed installation and setup steps with environment configuration - Include quick test commands for immediate validation - Clarify minimum requirements and optional dependencies - Add debug tools endpoint information - Update feature status to reflect production-ready core functionality - Remove database dependencies from requirements (not needed for core features) - Update environment variables table with proper requirements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix missing newline at end of file - Update multi-provider LLM status to reflect current implementation (OpenAI, Anthropic) - Maintain clean documentation formatting 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove database connection checks and initialization from main.py - Remove database-dependent routers (workers, bridge, plugins, jobs) - Keep only core functionality: chat, health, and debug endpoints - Simplify application lifespan to only include essential components - Remove database test endpoint - Core UPEE functionality now works without any database setup This allows the application to start and run with just LLM API keys, making setup much simpler for core chat functionality. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Update start script to check only core dependencies (fastapi, uvicorn, pydantic, httpx, openai) - Add comprehensive test script to verify no-database functionality - Confirm all SQLAlchemy references are in unused files not imported by main app - Core application (chat, health, debug) works completely without database Test results: ✅ All 3 tests passed - Import test: Core components import successfully - App creation test: FastAPI app created with core routes - Server startup test: Server starts and health check passes The application now runs entirely without database dependencies while maintaining full UPEE functionality, multi-LLM support, and file processing. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
* Fix dependency resolution issues in requirements.txt - Relaxed version constraints to avoid 'resolution-too-deep' error - Improved Python 3.13 compatibility - Backed up original requirements to requirements.txt.original - Core packages now install successfully * Add GitHub Actions workflow for automated testing - Created .github/workflows/test.yml with comprehensive test pipeline - Added python test_no_db.py execution as requested - Included pytest, flake8 linting, and mypy type checking - Support for Python 3.11, 3.12, 3.13 matrix testing - Added pip caching for faster builds - Triggers on push/PR to main/develop branches * Add fix-requirements branch to GitHub Actions triggers - Added fix-requirements to push trigger branches - This will allow testing the current branch * Configure GitHub Actions to run on all branches - Removed branch restrictions for push and pull_request triggers - Now fires on any push to any branch and any PR - Simplifies workflow management and ensures all code is tested * Simplify GitHub Actions workflow - Run only on pull_request (not on every push) - Use single Python version (3.13) instead of matrix - Reduces unnecessary test runs and CI overhead - Still runs python test_no_db.py as core test * Rename GitHub Actions workflow to test_no_db - Changed workflow name from 'Tests' to 'test_no_db' - Better reflects the core test being executed * Fix GitHub Actions dependency resolution issues - Pin boto3, aioboto3, and jmespath versions to avoid resolution conflicts - Add multi-stage pip install strategy with fallback options - Use legacy resolver as backup for complex dependency graphs - Add timeout and no-deps options for edge cases * fire action * Fix GitHub Actions for fork PRs - Add pull_request_target trigger for fork PRs - Add debug information to troubleshoot workflow execution - Add push trigger for branch testing - Create separate fork-specific workflow - Add proper checkout configuration for PR head - Set timeout to prevent hanging jobs * remove fork-pr-test * Simplify GitHub Actions triggers to PR events only Remove redundant push and pull_request_target triggers to prevent duplicate workflow runs and eliminate potential security risks from pull_request_target. * Consolidate flake8 configuration for better maintainability - Create .flake8 configuration file with all linting options - Simplify GitHub Actions workflow to use single flake8 command - Centralize linting rules for consistency across development and CI
Implements a comprehensive agent discovery and communication framework that enables the PAF Core Agent to leverage external specialized agents for enhanced processing. Key features: - Agent discovery via 'pixell list' command with periodic refresh - Intelligent agent selection based on context and complexity - Multi-protocol support (HTTP/REST, gRPC, WebSocket) - Integration with UPEE engine phases (Understand and Plan) - Health monitoring and usage statistics tracking - Graceful fallback to local processing when agents unavailable New components: - app/agents/: Core agent management module - models.py: Data models for agent communication - manager.py: Agent orchestration and decision logic - discovery.py: Agent discovery and registry management - client.py: Multi-protocol communication client - app/api/agents.py: REST API endpoints for agent management - app/api/dependencies.py: Singleton UPEE engine management Modified components: - app/core/upee_engine.py: Integrated AgentManager into UPEE processing - app/core/understand.py: Added agent enhancement support - app/core/plan.py: Added agent enhancement support - app/main.py: Included agents router This enables the PAF Core Agent to distribute complex or domain-specific tasks to specialized agents while maintaining local processing capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add language detection using LLM in understanding phase - Pass language information through UPEE phases properly - Add language instructions to system prompt for non-English languages - Fix bug where Korean requests were getting English responses - Handle JSON parsing with markdown code blocks in LLM responses 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit fixes the issue where conversation history was not being preserved between messages in the chat. The core agent now properly maintains context across multi-turn conversations. Key changes: - Added LLMMessage class to represent individual conversation messages - Updated LLMRequest to support messages array alongside legacy prompt field - Modified execute phase to build messages array from conversation history - Updated all LLM providers (OpenAI, Claude, Bedrock) to handle messages format - Added comprehensive tests for conversation memory preservation - Enhanced CSV file processing with better table formatting support - Added language-aware response generation - Added table generation detection and formatting The system now passes the full conversation history to LLM providers, allowing the assistant to maintain context and reference previous messages in the conversation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Added UI capabilities pass-through from client to agents - Implemented UI event forwarding (ui.render, ui.patch, action.result) - Added /api/bridge/ui/event endpoint for UI event handling - Added docs/ to .gitignore - Added AGPL-3.0 license with commercial licensing option - Updated README with license information 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Renamed app/ directory to src/ (APKG requirement) - Updated all Python imports from 'app.' to 'src.' - Updated test imports - Added Phase 1 completion summary - Added test_phase1_imports.py for validation Test results: 9/13 modules pass (4 fail due to pre-existing langchain dep issue) Phase 1 COMPLETE ✅
- Added src/par_adapter.py with PAR-compatible interfaces - Implemented mount(app) for REST route mounting - Implemented create_service() for gRPC handlers - Added initialize() and shutdown() lifecycle hooks - Created test_phase2_adapter.py for validation - Added Phase 2 completion summary All required functions verified present and syntactically valid. Phase 2 COMPLETE ✅
- Added agent.yaml with complete metadata - Specified REST entrypoint: src.par_adapter:mount - Specified gRPC entrypoint: src.par_adapter:create_service - Listed all agent capabilities - Added comprehensive usage guide with examples - Included REST and gRPC code samples - Added Phase 3 completion summary Validated with pixell validate - SUCCESS ✅ Phase 3 COMPLETE ✅
Phase 4: - Added .env.example with comprehensive configuration template - Documented all environment variables with comments Phase 5: - Updated src/main.py with DEV-MODE-ONLY warnings - Fixed import path from 'app.main:app' to 'src.main:app' - Added clear documentation that PAR uses par_adapter, not main.py Both phases COMPLETE ✅
- Phase 1: Directory rename and import validation - Phase 2: PAR adapter implementation validation - Phase 3: agent.yaml manifest validation - Phase 4: .env.example configuration validation - Phase 5: main.py updates validation - Phase 6: APKG build and packaging validation - Master test runner for all phases All tests pass successfully ✅
All 6 phases tested and validated: - Phase 1: Directory Rename ✅ - Phase 2: PAR Adapter ✅ - Phase 3: Agent Manifest ✅ - Phase 4: Configuration ✅ - Phase 5: Main.py Updates ✅ - Phase 6: APKG Build ✅ Total: 120 checks passed, 0 failed Package ready for deployment
- Copy agent.proto and generated Python files to src/proto/ - Fix relative imports in agent_pb2_grpc.py - Add test_proto_imports.py to verify proto setup - All tests passing ✅ Related to #6
- Create GrpcAgentCardClient for fetching agent cards via gRPC - Implement PathPrefixInterceptor for PAR's ALB routing - Support TLS connections to par.pixell.global:443 - Parse DescribeCapabilities response into agent card format - All tests passing ✅ - Successfully tested against deployed PAF Core Agent Related to #6
- Modified agent_app_discovery.py to try gRPC first for PAR agents - Falls back to HTTP if gRPC fails or for non-PAR agents - Created comprehensive test suite with: - Unit tests for gRPC fetch - Unit tests for HTTP fetch - Fallback mechanism tests - Integration test with real PAR-deployed agent - All tests passing including integration test This fixes Issue #6 (Agent card fetch fails for PAR-deployed agents) by using gRPC DescribeCapabilities instead of HTTP /.well-known/agent.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Added A2A_AGENT_APPS to agent.yaml environment section - Updated .env.example with A2A_AGENT_APPS example configuration - Added A2A_CARD_REFRESH_INTERVAL to .env.example - Included Vivid Commenter agent as example configuration This fixes Issue #7 (APKG deployment missing A2A_AGENT_APPS configuration) by ensuring environment variables are included in agent.yaml for PAR deployment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Documents all 6 implementation phases - Includes technical details and code examples - Lists all errors encountered and fixes - Complete test coverage summary - Deployment readiness checklist - Expected behavior before/after fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixes #8 - A2A gRPC Invoke calls failing due to incorrect agent_id in path ## Problem When PAF-Core invokes another agent via A2A gRPC (e.g., vivid-commenter), the call fails with UNIMPLEMENTED because the gRPC path uses PAF-Core's agent_id instead of the target agent's agent_id. **Wrong**: /agents/ed8784f3-.../a2a/pixell.agent.AgentService/Invoke **Correct**: /agents/4906eeb7-.../a2a/pixell.agent.AgentService/Invoke ## Solution ### 1. Created GrpcA2AClient (src/agents/grpc_a2a_client.py) - gRPC-based A2A client for Invoke calls - Uses **target agent's** agent_app_id in path prefix - Reuses PathPrefixInterceptor pattern from GrpcAgentCardClient - Converts message payload to proto ActionRequest - Returns standardized response format ### 2. Created HybridAgentClient (src/agents/hybrid_agent_client.py) - Smart client that auto-detects HTTP vs gRPC based on agent config - Uses gRPC for PAR-deployed agents (par.pixell.global) - Uses HTTP for local/direct agents - Supports force_grpc option for testing ### 3. Updated AgentClientPool (src/agents/agent_client_pool.py) - Changed from AgentClient to HybridAgentClient - Passes full agent info (not just endpoint_url) - Logs protocol being used (grpc/http) for debugging ## Testing - Created comprehensive test suite (test_grpc_a2a_invoke.py) - All tests passing ✅ - Verified correct path prefix construction - Verified protocol detection logic ## Key Implementation Detail The critical fix is in GrpcA2AClient.__init__: ```python def __init__(self, agent_app_id: str, endpoint_url: str, timeout: float = 30.0): self.agent_app_id = agent_app_id # TARGET agent's ID (not caller's) async def send_message(self, message: Dict[str, Any]): path_prefix = f"/agents/{self.agent_app_id}/a2a" # Uses TARGET agent ``` This ensures vivid-commenter receives: - Path: /agents/4906eeb7-.../a2a/pixell.agent.AgentService/Invoke - PAR interceptor strips prefix correctly - Method /pixell.agent.AgentService/Invoke reaches handler 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixes #9 ## Problem PAF Core Agent deployed via PAR/APKG failed to route requests to downstream A2A agents (e.g., Vivid Commenter). Instead, PAF Core answered all requests directly, making multi-agent coordination completely broken in production. Root cause: Architectural mismatch between dev (main.py) and prod (par_adapter.py). Development mode initialized multi-agent components once at startup and reused them. Production mode created new UPEE Engine per request without registry/selector, causing discovery service to never complete initialization before shutdown. ## Solution Add PAR application lifecycle hooks to initialize multi-agent components once at startup and reuse across all requests. ### Changes **1. PAR Adapter Lifecycle (src/par_adapter.py)** - Add `startup()` hook to initialize discovery service, registry, selector, and client pool at PAR application startup - Add `shutdown()` hook to clean up components on PAR shutdown - Store components in module-level state for reuse across requests - Update `handle_chat_request()` to use components from global state - Add comprehensive logging for initialization and routing decisions **2. UPEE Engine Multi-Agent Support (src/core/upee_engine.py)** - Accept optional `registry`, `selector`, `client_pool` parameters - Detect multi-agent mode vs legacy mode based on components - Only initialize AgentManager in legacy mode (for backward compatibility) - Pass components to PlanPhase and ExecutePhase - Update startup/shutdown to handle both modes **3. Plan Phase Debug Logging (src/core/plan.py)** - Add debug logging before multi-agent routing checks - Log when multi-agent match found with agent/skill details - Add warning when selector/registry not initialized - Log why routing is unavailable for easier debugging ### Tests **Unit Tests (15 total)** - `tests/test_par_adapter_lifecycle.py` (8 tests) - startup initializes all components - shutdown cleans up resources - state persists across calls - graceful error handling - `tests/test_upee_engine_multiagent.py` (7 tests) - multi-agent mode vs legacy mode detection - components passed to phases correctly - startup/shutdown behavior differs by mode - partial components trigger legacy mode **Integration Tests (3 total)** - `tests/integration/test_routing_flow.py` - Full routing flow for subreddit query → Vivid Commenter - Non-matching queries handled directly by PAF Core - Graceful degradation when components not initialized **Result: All 18 tests PASSED** ✅ ## Impact - ✅ Fixes 100% routing failure in production - ✅ Enables multi-agent coordination via A2A protocol - ✅ Maintains backward compatibility with dev mode (main.py) - ✅ Gracefully degrades when components not initialized - ✅ Comprehensive logging for debugging routing decisions ## Testing ```bash # Unit & integration tests pytest tests/test_par_adapter_lifecycle.py -v # 8/8 PASSED pytest tests/test_upee_engine_multiagent.py -v # 7/7 PASSED pytest tests/integration/test_routing_flow.py -v # 3/3 PASSED # Full suite pytest tests/ -v # 18/18 PASSED ``` ## Deployment Notes PAR will automatically call `startup()` when loading the agent and `shutdown()` when unloading. No configuration changes required. Verify logs on startup show: - "🚀 PAF-Core Agent startup: Initializing multi-agent components" - "✅ PAF-Core Agent startup complete" - "Multi-agent startup complete" with agent counts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Major milestone: Core AI routing infrastructure is complete and tested. ## Phase 1: Static Agent Configuration ✓ - Created agents_config.json with Vivid Commenter metadata - Implemented src/config/agent_loader.py with caching - Loads agents from file + A2A_AGENT_APPS env variable - 17 tests passing ## Phase 2: LangGraph State Structure ✓ - Created src/langgraph_upee/state.py with UPEEState TypedDict - Designed state to flow through UPEE graph nodes - Includes routing decisions, agent selection, quality metrics - 11 tests passing ## Phase 3: Understand Node ✓ - Implemented AI-powered intent analysis - Uses LLM to extract intent, topics, entities, complexity - Fallback to rule-based analysis if LLM fails - 10 tests passing ## Phase 4: AI-Powered Routing Node ✓ **CRITICAL** - Intelligent routing using LLM analysis (not keyword matching!) - LLM reads agent capabilities and example queries - Decides: "core" or "agent" with confidence + reasoning - Fallback routing for reliability - 11 tests passing **Total: 49 tests passing, 0 failures** This completes the intelligent routing core of the system. The AI now understands user intent and can intelligently route Reddit queries to Vivid Commenter instead of handling them with PAF Core. Next: Execute nodes to actually call the agents (Phases 5-6). 🧠 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
## Phase 5: Execute PAF Core Node ✓ - Handles requests routed to PAF Core (routing_decision="core") - Uses LLM to generate responses for general queries - Includes conversation history and file context in prompts - Graceful error handling with user-friendly messages - 11 tests passing ## Phase 6: Execute Agent Node (A2A gRPC) ✓ - Handles requests routed to specialized agents (routing_decision="agent") - Uses GrpcA2AClient to make A2A calls to agents like Vivid Commenter - Builds proper A2A message payloads with conversation history and files - Extracts response content from various A2A response formats - Includes routing metadata in A2A calls for observability - 14 tests passing **Progress: 74/74 tests passing (100%)** These execution nodes complete the action phase of the UPEE loop. When AI routing decides "core", execute_core generates response with LLM. When AI routing decides "agent", execute_agent calls the selected A2A agent via gRPC. Next: Evaluate node (Phase 7) to assess response quality. 🧠 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
## Phase 7: Evaluate Node ✓ - AI-powered response quality assessment - Uses LLM to evaluate accuracy, completeness, relevance, clarity - Generates quality score (0.0-1.0) and detailed feedback - Determines if refinement needed - Fallback evaluation for reliability - 11 tests passing **Total: 85/85 tests passing (100%)** All individual nodes now complete: - ✓ Understand: Extract intent and context - ✓ Routing: AI-powered routing decision - ✓ Execute Core: Generate response with LLM - ✓ Execute Agent: Call A2A agents via gRPC - ✓ Evaluate: Assess response quality Next: Phase 8 - Assemble these nodes into working LangGraph with conditional edges. 🧠 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
## Phase 8: LangGraph Assembly ✓ **CRITICAL** - Assembled all nodes into working LangGraph with conditional edges - Created graph.py with build_upee_graph() and execute_upee_graph() - Implemented conditional routing based on AI routing decisions - Graph flow: Understand → Routing → [Core|Agent] → Evaluate → END - Comprehensive integration tests for core path, agent path, conversation history - Tests error handling and fallback mechanisms - 7 integration tests passing **Graph Structure:** ``` START ↓ Understand (AI extracts intent) ↓ Routing (AI decides: core or agent) ├──→ [if "core"] Execute Core (LLM generates response) └──→ [if "agent"] Execute Agent (gRPC A2A call) ↓ Evaluate (AI assesses quality) ↓ END ``` **Total: 92/92 tests passing (100%)** - Phase 1: Agent config (17 tests) - Phase 2: State structure (11 tests) - Phase 3: Understand (10 tests) - Phase 4: AI Routing - CRITICAL (11 tests) - Phase 5: Execute Core (11 tests) - Phase 6: Execute Agent (14 tests) - Phase 7: Evaluate (11 tests) - Phase 8: Graph Assembly - CRITICAL (7 tests) 🎉 **MAJOR MILESTONE**: Complete AI-native routing system is now functional! The graph successfully routes Reddit queries to Vivid Commenter and general queries to PAF Core, with full AI-powered decision making at every step. Next: Integrate into UPEE Engine (Phase 9) to replace current UPEE loop. 🧠 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit implements a complete AI-native routing system using LangGraph
that intelligently routes user queries to specialized agents like Vivid
Commenter for Reddit-related tasks.
## Key Changes
### 1. Static Agent Configuration (Phase 1)
- Created `agents_config.json` with Vivid Commenter agent metadata
- Created `src/config/agent_loader.py` for on-demand agent loading
- Eliminates complex discovery services and background tasks
### 2. LangGraph State Management (Phase 2)
- Created `src/langgraph_upee/state.py` with TypedDict-based state
- Defines UPEEState, UPEEInput, and UPEEOutput structures
- Type-safe state flowing through graph nodes
### 3. AI-Powered Nodes (Phases 3-7)
- **Understand Node**: LLM extracts user intent and context
- **Routing Node**: LLM decides core vs agent routing by analyzing capabilities
- **Execute Core Node**: Handles general queries with PAF Core LLM
- **Execute Agent Node**: Routes to A2A agents via gRPC
- **Evaluate Node**: LLM assesses response quality
### 4. LangGraph Assembly (Phase 8)
- Created `src/langgraph_upee/graph.py` assembling complete graph
- Implements conditional edges for routing decisions
- Graph flow: Understand → Routing → (Core | Agent) → Evaluate
### 5. UPEE Engine Integration (Phase 9)
- Modified `src/core/upee_engine.py` to support LangGraph
- Added `use_langgraph_upee` setting (default: True)
- Conditional routing between legacy UPEE and LangGraph
### 6. PAR Adapter Simplification (Phase 10)
- Removed lifecycle hooks from `src/par_adapter.py`
- Eliminated unused multi-agent discovery components
- Cleaner architecture with on-demand config loading
### 7. Comprehensive Testing (Phase 11)
- 84 passing tests for LangGraph implementation
- E2E test validating Reddit query → Vivid Commenter routing
- Tests for all nodes, graph assembly, and integration
## Architecture
```
User Query: "find me 10 subreddits related to ai"
↓
Understand Node (AI extracts intent: Reddit subreddit search)
↓
Routing Node (AI decision: route to Vivid Commenter)
↓
Execute Agent Node (gRPC call to Vivid Commenter)
↓
Evaluate Node (AI assesses quality: 0.92/1.0)
↓
Response: List of 10 AI subreddits
```
## Impact
- Fixes routing failure where Reddit queries weren't reaching Vivid Commenter
- Fully AI-native decision making at every step (no keyword matching)
- Leverages LangGraph's graph capabilities as requested
- Eliminates dependency on PAR lifecycle hooks
- Simpler, more maintainable architecture
## Testing
- 84 LangGraph tests passing (100% coverage)
- E2E test validates complete routing flow
- Tests removed for deprecated multi-agent system
Fixes #11
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The hasattr() check was failing in some cases. Changed to getattr() with explicit True default to ensure LangGraph routing is always enabled by default. Also added USE_LANGGRAPH_UPEE to .env.example for documentation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
## Problem
The `_create_completion_event()` method only extracted metadata from the legacy
UPEE structure, causing LangGraph-routed requests to show incorrect metadata:
- agent_app_id: None
- routing_source: 'core_agent'
Even though LangGraph was working correctly and routing to Vivid Commenter.
## Root Cause
Two UPEE implementations store metadata differently:
**LangGraph** stores in evaluate_result.metadata:
- routing_decision: "agent"
- selected_agent_name: "Vivid Commenter"
- (missing agent_app_id)
**Legacy UPEE** stores in execute_result.metadata.external_results.a2a_agent:
- agent_app_id: "..."
- agent_name: "..."
- status: "success"
_create_completion_event() only looked for the legacy structure, so LangGraph
always showed "core_agent" metadata.
## Solution
1. Added selected_agent_id to UPEEOutput TypedDict
2. Modified LangGraph graph.py to include agent_app_id in output
3. Store agent_id + langgraph_execution flag in phase_results
4. Updated _create_completion_event() to detect LangGraph and extract metadata
from the correct location (evaluate_result instead of execute_result)
5. Added test to verify completion metadata is correct
## Impact
After this fix, Reddit queries routed to Vivid Commenter will show:
```python
'metadata': {
'agent_used': 'Vivid Commenter',
'agent_app_id': '4906eeb7-9959-414e-84c6-f2445822ebe4',
'routing_source': 'langgraph_agent', # ← Changed from 'core_agent'
}
```
## Testing
✅ 85 tests passing (added 1 new test for metadata validation)
✅ All E2E LangGraph routing tests pass
✅ Metadata extraction works for both LangGraph and legacy paths
Fixes #11
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements a complete AI-native routing system using LangGraph that intelligently routes user queries to specialized agents. This fixes the issue where Reddit-related queries like "find me 10 subreddits related to ai" were not being routed to the Vivid Commenter agent.
Problem Statement
Previously, PAF Core Agent was failing to route Reddit queries to the Vivid Commenter agent (ID: 4906eeb7-9959-414e-84c6-f2445822ebe4). Instead, it handled them directly with OpenAI, showing:
agent_app_id: Nonerouting_source: 'core_agent'This was caused by lifecycle hooks in
par_adapter.pynever being called by PAR's architecture.Solution
Implemented a fully AI-native routing system using LangGraph with the following architecture:
Key Changes
1. Static Agent Configuration (Phase 1)
agents_config.jsonwith Vivid Commenter metadatasrc/config/agent_loader.pyfor on-demand loading2. LangGraph State Management (Phase 2)
src/langgraph_upee/state.pywith TypedDict-based state3. AI-Powered Nodes (Phases 3-7)
4. LangGraph Assembly (Phase 8)
5. UPEE Engine Integration (Phase 9)
src/core/upee_engine.pyto support LangGraphuse_langgraph_upeesetting (default: True)6. PAR Adapter Simplification (Phase 10)
src/par_adapter.py7. Comprehensive Testing (Phase 11)
Test Results
Architecture Details
LangGraph Flow
The system uses LangGraph's StateGraph with conditional edges:
Understand Node - AI analyzes user message
Routing Node - AI makes intelligent routing decision
agents_config.jsonExecute Core/Agent Node - Conditional execution
Evaluate Node - AI assesses response
No Lifecycle Hook Dependency
The old approach required:
startup()hook to initialize discovery serviceThe new approach:
Impact
Deployment
To deploy:
mainpixell buildpixell deploy"find me 10 subreddits related to ai"Configuration
Enable LangGraph routing (default):
USE_LANGGRAPH_UPEE=true # defaultVivid Commenter is configured in
agents_config.jsonand can also be overridden via environment:A2A_AGENT_APPS='[{"agent_app_id":"4906eeb7-9959-414e-84c6-f2445822ebe4","name":"Vivid Commenter",...}]'Fixes #11
🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com