refactor: fix architectural issues across frontend and backend
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.
This commit is contained in:
@@ -8,7 +8,8 @@ from unittest.mock import AsyncMock, MagicMock
|
||||
import pytest
|
||||
from langgraph.checkpoint.memory import InMemorySaver
|
||||
|
||||
from app.graph import build_agent_nodes, build_graph, classify_intent
|
||||
from app.graph import build_agent_nodes, build_graph
|
||||
from app.graph_context import GraphContext
|
||||
from app.intent import ClassificationResult, IntentTarget
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -37,8 +38,9 @@ class TestBuildGraph:
|
||||
mock_llm.with_structured_output = MagicMock(return_value=mock_llm)
|
||||
checkpointer = InMemorySaver()
|
||||
|
||||
graph = build_graph(sample_registry, mock_llm, checkpointer)
|
||||
assert graph is not None
|
||||
graph_ctx = build_graph(sample_registry, mock_llm, checkpointer)
|
||||
assert graph_ctx is not None
|
||||
assert graph_ctx.graph is not None
|
||||
|
||||
def test_graph_has_classifier_attached(self, sample_registry: AgentRegistry) -> None:
|
||||
mock_llm = MagicMock()
|
||||
@@ -47,11 +49,11 @@ class TestBuildGraph:
|
||||
checkpointer = InMemorySaver()
|
||||
mock_classifier = MagicMock()
|
||||
|
||||
graph = build_graph(
|
||||
graph_ctx = build_graph(
|
||||
sample_registry, mock_llm, checkpointer, intent_classifier=mock_classifier
|
||||
)
|
||||
assert graph.intent_classifier is mock_classifier
|
||||
assert graph.agent_registry is sample_registry
|
||||
assert graph_ctx.intent_classifier is mock_classifier
|
||||
assert graph_ctx.registry is sample_registry
|
||||
|
||||
def test_graph_without_classifier(self, sample_registry: AgentRegistry) -> None:
|
||||
mock_llm = MagicMock()
|
||||
@@ -59,17 +61,18 @@ class TestBuildGraph:
|
||||
mock_llm.with_structured_output = MagicMock(return_value=mock_llm)
|
||||
checkpointer = InMemorySaver()
|
||||
|
||||
graph = build_graph(sample_registry, mock_llm, checkpointer)
|
||||
assert graph.intent_classifier is None
|
||||
graph_ctx = build_graph(sample_registry, mock_llm, checkpointer)
|
||||
assert graph_ctx.intent_classifier is None
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestClassifyIntent:
|
||||
@pytest.mark.asyncio
|
||||
async def test_returns_none_without_classifier(self) -> None:
|
||||
graph = MagicMock()
|
||||
graph.intent_classifier = None
|
||||
result = await classify_intent(graph, "hello")
|
||||
mock_registry = MagicMock()
|
||||
mock_registry.list_agents = MagicMock(return_value=())
|
||||
graph_ctx = GraphContext(graph=MagicMock(), registry=mock_registry, intent_classifier=None)
|
||||
result = await graph_ctx.classify_intent("hello")
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -80,11 +83,12 @@ class TestClassifyIntent:
|
||||
mock_classifier = AsyncMock()
|
||||
mock_classifier.classify = AsyncMock(return_value=expected)
|
||||
|
||||
graph = MagicMock()
|
||||
graph.intent_classifier = mock_classifier
|
||||
graph.agent_registry = MagicMock()
|
||||
graph.agent_registry.list_agents = MagicMock(return_value=())
|
||||
mock_registry = MagicMock()
|
||||
mock_registry.list_agents = MagicMock(return_value=())
|
||||
graph_ctx = GraphContext(
|
||||
graph=MagicMock(), registry=mock_registry, intent_classifier=mock_classifier,
|
||||
)
|
||||
|
||||
result = await classify_intent(graph, "check order")
|
||||
result = await graph_ctx.classify_intent("check order")
|
||||
assert result is not None
|
||||
assert result.intents[0].agent_name == "order_lookup"
|
||||
|
||||
Reference in New Issue
Block a user