| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- """Thin workflow state.
- Search pages, candidates, evidence and final buckets stay in the existing database.
- This state only contains orchestration pointers and audit summaries.
- """
- from __future__ import annotations
- from dataclasses import dataclass, field
- from typing import Any, Literal, TypedDict
- from supply_agent.types import AgentResult
- Phase = Literal["planning", "searching", "evidence", "evaluating", "done"]
- SupervisorAction = Literal["search", "evidence", "evaluator", "finish"]
- EndKind = Literal["goal_met", "partial", "no_match", "failed", "stopped"]
- @dataclass(frozen=True)
- class DiscoverySnapshot:
- """Small deterministic projection of the database state."""
- status: str
- search_count: int
- candidate_count: int
- pending_count: int
- primary_count: int
- valid_primary_count: int
- rejected_count: int
- outcome_status: str = ""
- @dataclass(frozen=True)
- class NodeRun:
- """One node's observable result."""
- node: str
- round_index: int
- content: str
- iterations: int
- tool_calls_made: int
- @classmethod
- def from_agent_result(
- cls,
- node: str,
- round_index: int,
- result: AgentResult,
- ) -> "NodeRun":
- return cls(
- node=node,
- round_index=round_index,
- content=result.content or "",
- iterations=int(result.iterations or 0),
- tool_calls_made=int(result.tool_calls_made or 0),
- )
- @dataclass
- class FindAgentState:
- """Control state passed through the single-round graph."""
- run_id: str
- user_input: str
- round_index: int = 0
- phase: Phase = "planning"
- plan: str = ""
- stop: bool = False
- stop_reason: str = ""
- previous_snapshot: DiscoverySnapshot | None = None
- snapshot: DiscoverySnapshot | None = None
- node_runs: list[NodeRun] = field(default_factory=list)
- failures: list[dict[str, Any]] = field(default_factory=list)
- class FindAgentGraphState(TypedDict, total=False):
- """Serializable state used by the real one-round LangGraph."""
- run_id: str
- user_input: str
- round_index: int
- plan: str
- phase: Phase
- node_runs: list[NodeRun]
- snapshot: DiscoverySnapshot | None
- supervisor_step: int
- approved_action: SupervisorAction
- action_count: int
- search_actions: int
- worker_count: int
- evidence_scope: str
- decision_history: list[dict[str, Any]]
- evaluator_stagnation: int
- @dataclass(frozen=True)
- class FindAgentResult:
- """Workflow result with technical and business status kept separate."""
- run_id: str
- status: EndKind
- succeeded: bool
- business_outcome: str
- valid_primary_count: int
- rounds: int
- final_output: str
- node_runs: tuple[NodeRun, ...]
- stop_reason: str = ""
- @property
- def iterations(self) -> int:
- return sum(item.iterations for item in self.node_runs)
- @property
- def tool_calls_made(self) -> int:
- return sum(item.tool_calls_made for item in self.node_runs)
|