Refactor workflow agent and routing components for improved functionality
- Introduce WorkflowAgentStage to manage agent stage configurations and enhance interaction with the workflow engine. - Implement WorkflowEdgeEvaluator for priority-aware edge evaluation, improving routing decisions based on conditions and user turns. - Update WorkflowBrain to handle user turns and routing more effectively, ensuring agents cannot have only one default path. - Enhance CallEndCoordinator to track speech events and manage call termination based on queued speech. - Add new models and output handling for workflow interactions, improving clarity and maintainability. - Update tests to validate the new routing logic and agent behavior under various scenarios.
This commit is contained in:
92
backend/services/workflow/models.py
Normal file
92
backend/services/workflow/models.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""Readable runtime values shared by Workflow orchestration modules."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
from typing import Any
|
||||
|
||||
|
||||
class WorkflowStatus(StrEnum):
|
||||
"""The small set of states useful to operators and future debug tooling."""
|
||||
|
||||
STARTING = "starting"
|
||||
WAITING_USER = "waiting_user"
|
||||
ROUTING = "routing"
|
||||
RUNNING_AGENT = "running_agent"
|
||||
RUNNING_ACTION = "running_action"
|
||||
HANDOFF = "handoff"
|
||||
ENDED = "ended"
|
||||
|
||||
|
||||
class RouteStatus(StrEnum):
|
||||
"""A routing error is deliberately different from a valid no-match."""
|
||||
|
||||
MATCHED = "matched"
|
||||
NO_MATCH = "no_match"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UserTurn:
|
||||
"""One committed user turn that may cross automatic Workflow nodes."""
|
||||
|
||||
id: int
|
||||
text: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class WorkflowRuntimeState:
|
||||
"""Mutable per-call state; graph definitions remain immutable."""
|
||||
|
||||
current_node_id: str
|
||||
status: WorkflowStatus = WorkflowStatus.STARTING
|
||||
pending_user_turn: UserTurn | None = None
|
||||
transition_id: int = 0
|
||||
automatic_hops: int = 0
|
||||
ended: bool = False
|
||||
_next_turn_id: int = 1
|
||||
|
||||
def begin_user_turn(self, text: str) -> UserTurn:
|
||||
turn = UserTurn(id=self._next_turn_id, text=text)
|
||||
self._next_turn_id += 1
|
||||
self.pending_user_turn = turn
|
||||
self.automatic_hops = 0
|
||||
return turn
|
||||
|
||||
def enter(self, node_id: str, status: WorkflowStatus) -> None:
|
||||
self.current_node_id = node_id
|
||||
self.status = status
|
||||
|
||||
def begin_transition(self) -> int:
|
||||
self.transition_id += 1
|
||||
return self.transition_id
|
||||
|
||||
def consume_user_turn(self) -> UserTurn | None:
|
||||
turn = self.pending_user_turn
|
||||
self.pending_user_turn = None
|
||||
return turn
|
||||
|
||||
def finish(self) -> None:
|
||||
self.ended = True
|
||||
self.status = WorkflowStatus.ENDED
|
||||
self.pending_user_turn = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LLMRouteResult:
|
||||
"""Control-plane result returned by the small routing LLM."""
|
||||
|
||||
status: RouteStatus
|
||||
function_name: str | None = None
|
||||
error: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EdgeEvaluation:
|
||||
"""Final graph-level decision after expression, LLM and default handling."""
|
||||
|
||||
status: RouteStatus
|
||||
edge: dict[str, Any] | None = None
|
||||
error: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user