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:
@@ -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__)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user