fix: resolve ruff lint errors in Phase 2 code

- Move intent imports to TYPE_CHECKING block in graph.py (TC001)
- Rename test classes to CapWords convention (N801)
- Fix line length violations across test files (E501)
- Auto-fix import sorting (I001)
This commit is contained in:
Yaojia Wang
2026-03-30 21:44:47 +02:00
parent b861ff055f
commit 006b4ee5d7
6 changed files with 40 additions and 20 deletions

View File

@@ -9,13 +9,13 @@ from langgraph.prebuilt import create_react_agent
from langgraph_supervisor import create_supervisor from langgraph_supervisor import create_supervisor
from app.agents import get_tools_by_names from app.agents import get_tools_by_names
from app.intent import ClassificationResult, IntentClassifier
if TYPE_CHECKING: if TYPE_CHECKING:
from langchain_core.language_models import BaseChatModel from langchain_core.language_models import BaseChatModel
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from langgraph.graph.state import CompiledStateGraph from langgraph.graph.state import CompiledStateGraph
from app.intent import ClassificationResult, IntentClassifier
from app.registry import AgentRegistry from app.registry import AgentRegistry
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@@ -90,7 +90,7 @@ def _agent(name: str, desc: str, perm: str = "read") -> AgentConfig:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.mark.integration @pytest.mark.integration
class TestCheckpoint1_OrderQueryRouting: class TestCheckpoint1OrderQueryRouting:
"""Verify intent classifier routes order queries to order_lookup.""" """Verify intent classifier routes order queries to order_lookup."""
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -161,7 +161,7 @@ class TestCheckpoint1_OrderQueryRouting:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.mark.integration @pytest.mark.integration
class TestCheckpoint2_MultiIntentSequential: class TestCheckpoint2MultiIntentSequential:
"""Verify multi-intent classified and hint injected for sequential execution.""" """Verify multi-intent classified and hint injected for sequential execution."""
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -235,7 +235,7 @@ class TestCheckpoint2_MultiIntentSequential:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.mark.integration @pytest.mark.integration
class TestCheckpoint3_AmbiguousClarification: class TestCheckpoint3AmbiguousClarification:
"""Verify ambiguous messages trigger clarification prompt.""" """Verify ambiguous messages trigger clarification prompt."""
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -263,7 +263,9 @@ class TestCheckpoint3_AmbiguousClarification:
mock_classifier.classify = AsyncMock(return_value=ClassificationResult( mock_classifier.classify = AsyncMock(return_value=ClassificationResult(
intents=(), intents=(),
is_ambiguous=True, is_ambiguous=True,
clarification_question="Could you please provide more details about what you need help with?", clarification_question=(
"Could you please provide more details about what you need help with?"
),
)) ))
graph.intent_classifier = mock_classifier graph.intent_classifier = mock_classifier
mock_registry = MagicMock() mock_registry = MagicMock()
@@ -294,7 +296,7 @@ class TestCheckpoint3_AmbiguousClarification:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.mark.integration @pytest.mark.integration
class TestCheckpoint4_InterruptTTLAutoCancel: class TestCheckpoint4InterruptTTLAutoCancel:
"""Verify interrupt TTL expiration triggers auto-cancel and retry prompt.""" """Verify interrupt TTL expiration triggers auto-cancel and retry prompt."""
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -361,7 +363,7 @@ class TestCheckpoint4_InterruptTTLAutoCancel:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.mark.integration @pytest.mark.integration
class TestCheckpoint5_WebhookEscalation: class TestCheckpoint5WebhookEscalation:
"""Verify webhook escalation sends POST and retries on failure.""" """Verify webhook escalation sends POST and retries on failure."""
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -442,7 +444,7 @@ class TestCheckpoint5_WebhookEscalation:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@pytest.mark.integration @pytest.mark.integration
class TestCheckpoint6_EcommerceTemplate: class TestCheckpoint6EcommerceTemplate:
"""Verify e-commerce template loads with correct agents.""" """Verify e-commerce template loads with correct agents."""
def test_ecommerce_template_loads_4_agents(self) -> None: def test_ecommerce_template_loads_4_agents(self) -> None:

View File

@@ -24,7 +24,6 @@ from app.registry import AgentConfig
from app.session_manager import SessionManager from app.session_manager import SessionManager
from app.ws_handler import dispatch_message from app.ws_handler import dispatch_message
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Helpers # Helpers
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -78,10 +77,22 @@ def _state(*, interrupt: bool = False, data: dict | None = None):
AGENTS = ( AGENTS = (
AgentConfig(name="order_lookup", description="Looks up orders", permission="read", tools=["get_order_status", "get_tracking_info"]), AgentConfig(
AgentConfig(name="order_actions", description="Modifies orders", permission="write", tools=["cancel_order"]), name="order_lookup", description="Looks up orders",
AgentConfig(name="discount", description="Applies discounts", permission="write", tools=["apply_discount", "generate_coupon"]), permission="read", tools=["get_order_status", "get_tracking_info"],
AgentConfig(name="fallback", description="Handles unclear requests", permission="read", tools=["fallback_respond"]), ),
AgentConfig(
name="order_actions", description="Modifies orders",
permission="write", tools=["cancel_order"],
),
AgentConfig(
name="discount", description="Applies discounts",
permission="write", tools=["apply_discount", "generate_coupon"],
),
AgentConfig(
name="fallback", description="Handles unclear requests",
permission="read", tools=["fallback_respond"],
),
) )
@@ -136,7 +147,9 @@ class TestSingleIntentRouting:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_routes_to_order_lookup(self) -> None: async def test_routes_to_order_lookup(self) -> None:
result = ClassificationResult( result = ClassificationResult(
intents=(IntentTarget(agent_name="order_lookup", confidence=0.95, reasoning="status query"),), intents=(IntentTarget(
agent_name="order_lookup", confidence=0.95, reasoning="status query",
),),
) )
graph = _make_graph(result, [ graph = _make_graph(result, [
_tool_chunk("get_order_status", {"order_id": "1042"}, "order_lookup"), _tool_chunk("get_order_status", {"order_id": "1042"}, "order_lookup"),

View File

@@ -19,7 +19,6 @@ from app.interrupt_manager import InterruptManager
from app.session_manager import SessionManager from app.session_manager import SessionManager
from app.ws_handler import dispatch_message from app.ws_handler import dispatch_message
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Helpers # Helpers
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -182,7 +181,8 @@ class TestWebSocketInterruptApproval:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_interrupt_then_approve(self) -> None: async def test_interrupt_then_approve(self) -> None:
st_int = _state(interrupt=True, data={"action": "cancel_order", "order_id": "1042"}) st_int = _state(interrupt=True, data={"action": "cancel_order", "order_id": "1042"})
g = _graph(chunks=[], st=st_int, resume_chunks=[_chunk("Order 1042 cancelled.", "order_actions")]) resume = [_chunk("Order 1042 cancelled.", "order_actions")]
g = _graph(chunks=[], st=st_int, resume_chunks=resume)
g_, sm, im, cb, ws = _setup(graph=g) g_, sm, im, cb, ws = _setup(graph=g)
# Send message -> triggers interrupt # Send message -> triggers interrupt
@@ -209,7 +209,8 @@ class TestWebSocketInterruptApproval:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_interrupt_then_reject(self) -> None: async def test_interrupt_then_reject(self) -> None:
st_int = _state(interrupt=True) st_int = _state(interrupt=True)
g = _graph(chunks=[], st=st_int, resume_chunks=[_chunk("Order remains active.", "order_actions")]) resume = [_chunk("Order remains active.", "order_actions")]
g = _graph(chunks=[], st=st_int, resume_chunks=resume)
g_, sm, im, cb, ws = _setup(graph=g) g_, sm, im, cb, ws = _setup(graph=g)
await _send(ws, g_, sm, im, cb, content="Cancel order 1042") await _send(ws, g_, sm, im, cb, content="Cancel order 1042")

View File

@@ -16,8 +16,10 @@ from app.intent import (
from app.registry import AgentConfig from app.registry import AgentConfig
def _make_agent(name: str, desc: str = "test", permission: str = "read") -> AgentConfig: def _make_agent(name: str, desc: str = "test", perm: str = "read") -> AgentConfig:
return AgentConfig(name=name, description=desc, permission=permission, tools=["fallback_respond"]) return AgentConfig(
name=name, description=desc, permission=perm, tools=["fallback_respond"],
)
@pytest.mark.unit @pytest.mark.unit

View File

@@ -222,7 +222,9 @@ class TestHandleUserMessage:
im = InterruptManager() im = InterruptManager()
sm.touch("t1") sm.touch("t1")
await handle_user_message(ws, graph, sm, cb, "t1", "cancel order 1042", interrupt_manager=im) await handle_user_message(
ws, graph, sm, cb, "t1", "cancel order 1042", interrupt_manager=im,
)
# Interrupt should be registered # Interrupt should be registered
assert im.has_pending("t1") assert im.has_pending("t1")