Address all architecture review findings: P0 fixes: - Add API key authentication for admin endpoints (analytics, replay, openapi) and WebSocket connections via ADMIN_API_KEY env var - Add PostgreSQL-backed PgSessionManager and PgInterruptManager for multi-worker production deployments (in-memory defaults preserved) P1 fixes: - Implement actual tool generation in OpenAPI approve_job endpoint using generate_tool_code() and generate_agent_yaml() - Add missing clarification, interrupt_expired, and tool_result message handlers in frontend ChatPage P2 fixes: - Replace monkey-patching on CompiledStateGraph with typed GraphContext - Replace 9-param dispatch_message with WebSocketContext dataclass - Extract duplicate _envelope() into shared app/api_utils.py - Replace mutable module-level counter with crypto.randomUUID() - Remove hardcoded mock data from ReviewPage, use api.ts wrappers - Remove `as any` type escape from ReplayPage All 516 tests passing, 0 TypeScript errors.
37 lines
1.1 KiB
Python
37 lines
1.1 KiB
Python
"""GraphContext -- typed wrapper around the compiled graph and its dependencies."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from langgraph.graph.state import CompiledStateGraph
|
|
|
|
from app.intent import ClassificationResult, IntentClassifier
|
|
from app.registry import AgentRegistry
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GraphContext:
|
|
"""Bundles the compiled LangGraph graph with its associated services.
|
|
|
|
Replaces the previous pattern of monkey-patching attributes onto the
|
|
third-party CompiledStateGraph instance.
|
|
"""
|
|
|
|
graph: CompiledStateGraph
|
|
registry: AgentRegistry
|
|
intent_classifier: IntentClassifier | None = None
|
|
|
|
async def classify_intent(self, message: str) -> ClassificationResult | None:
|
|
"""Classify user intent using the attached classifier.
|
|
|
|
Returns None if no classifier is configured.
|
|
"""
|
|
if self.intent_classifier is None:
|
|
return None
|
|
|
|
agents = self.registry.list_agents()
|
|
return await self.intent_classifier.classify(message, agents)
|