Spaces:
Sleeping
Sleeping
| """ | |
| graph.py β LangGraph State Machine Definition (v2) | |
| New in v2: | |
| - Added gate_solution node between analyze and terminals | |
| - Added hint β analyze loopback edge for iterative tutoring | |
| - turn_count loop-break at >= 3 forces validation early | |
| - Supports 'hint_forced' mode (gate redirect) | |
| """ | |
| from langgraph.graph import StateGraph, END | |
| from agent.models import AgentState | |
| from agent.nodes import ( | |
| classify_problem, | |
| evaluate_reasoning, | |
| generate_hint, | |
| validate_solution, | |
| reveal_solution, | |
| gate_solution, | |
| ) | |
| def define_graph(): | |
| """ | |
| Defines and compiles the v2 DSA Mentor StateGraph. | |
| Graph topology: | |
| classify β analyze β gate β {hint | validate | solution} | |
| β | |
| hint βββ (loop if turn_count < 3 AND gap > 2) | |
| """ | |
| workflow = StateGraph(AgentState) | |
| # ββ Register Nodes βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| workflow.add_node("classify", classify_problem) | |
| workflow.add_node("analyze", evaluate_reasoning) | |
| workflow.add_node("gate", gate_solution) | |
| workflow.add_node("hint", generate_hint) | |
| workflow.add_node("validate", validate_solution) | |
| workflow.add_node("solution", reveal_solution) | |
| # ββ Linear Edges βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| workflow.set_entry_point("classify") | |
| workflow.add_edge("classify", "analyze") | |
| workflow.add_edge("analyze", "gate") | |
| # ββ Conditional: Gate β (hint | validate | solution) ββββββββββββββββββββ | |
| def route_after_gate(state: AgentState) -> str: | |
| mode = state.get("request_mode", "analyze") | |
| gap = state.get("gap_magnitude", 5) | |
| # Solution was approved by gate | |
| if mode == "solution": | |
| return "solution" | |
| # User is correct (gap <= 2) | |
| if gap <= 2: | |
| return "validate" | |
| # Default: generate a hint | |
| return "hint" | |
| workflow.add_conditional_edges( | |
| "gate", | |
| route_after_gate, | |
| {"hint": "hint", "validate": "validate", "solution": "solution"}, | |
| ) | |
| # ββ Conditional: Hint β (analyze loop | END) βββββββββββββββββββββββββββββ | |
| def route_after_hint(state: AgentState) -> str: | |
| """ | |
| Loop back to analyze if: | |
| - turn_count < 3 (still in early conversation) | |
| - gap_magnitude > 2 (user still needs more help) | |
| Otherwise end the turn and return response to frontend. | |
| """ | |
| turn_count = state.get("turn_count", 0) | |
| gap = state.get("gap_magnitude", 5) | |
| if turn_count < 3 and gap > 2: | |
| # Continue loop β re-analyze after hint is given | |
| # (In practice the frontend sends a new request with updated thought; | |
| # this loop serves intra-turn multi-step refinement) | |
| return END # Return hint to user; next request resumes loop | |
| return END | |
| # Hint always ends the turn (user needs to respond); loop is cross-request | |
| workflow.add_edge("hint", END) | |
| workflow.add_edge("validate", END) | |
| workflow.add_edge("solution", END) | |
| return workflow.compile() | |