Skip to main content

lc_agents/handoffs/
handoff.rs

1//! Handoff type definitions
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6
7/// A Handoff handover directive
8#[derive(Debug)]
9pub struct Handoff {
10    /// Name of the target Agent
11    pub target_agent: String,
12    /// Task description to hand over
13    pub task: String,
14    /// Handoff context
15    pub context: Option<HandoffContext>,
16}
17
18/// Handoff context - carries information to the target Agent
19#[derive(Debug)]
20pub struct HandoffContext {
21    /// Original request content
22    pub original_request: String,
23    /// Current execution result
24    pub current_result: Option<String>,
25    /// Current conversation summary (P2-4): carries the upstream conversation
26    /// summary to the target Agent on handoff, rather than transferring control
27    /// raw — the target Agent can continue the topic instead of starting over.
28    pub conversation_summary: Option<String>,
29    /// Additional metadata
30    pub metadata: HashMap<String, Value>,
31}
32
33impl HandoffContext {
34    /// Creates a handoff context, recording the original request.
35    pub fn new(original_request: impl Into<String>) -> Self {
36        Self {
37            original_request: original_request.into(),
38            current_result: None,
39            conversation_summary: None,
40            metadata: HashMap::new(),
41        }
42    }
43
44    /// Carries the current conversation summary.
45    pub fn with_summary(mut self, summary: impl Into<String>) -> Self {
46        self.conversation_summary = Some(summary.into());
47        self
48    }
49
50    /// Carries the current execution result.
51    pub fn with_result(mut self, result: impl Into<String>) -> Self {
52        self.current_result = Some(result.into());
53        self
54    }
55}
56
57/// Handoff result
58pub struct HandoffResult {
59    /// Name of the target Agent
60    pub agent_name: String,
61    /// Handoff execution result
62    pub result: String,
63    /// Next handoff directive (optional)
64    pub next_handoff: Option<Box<Handoff>>,
65}
66
67/// Handoff history record
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct HandoffRecord {
70    /// Source Agent name
71    pub from_agent: String,
72    /// Target Agent name
73    pub to_agent: String,
74    /// Task description handed over
75    pub task: String,
76    /// Handoff result
77    pub result: String,
78    /// Handoff timestamp
79    pub timestamp: String,
80}
81
82/// Handoff error
83#[derive(Debug)]
84#[non_exhaustive]
85pub enum HandoffError {
86    /// The target Agent does not exist
87    AgentNotFound(String),
88    /// Agent execution error
89    ExecutionError(String),
90    /// Handoff cycle detected: A hands off to B, B hands back to A, infinite loop (P1-7).
91    HandoffCycleDetected(String),
92    /// Handoff depth exceeded the limit (P1-7).
93    MaxHandoffDepthExceeded(usize),
94}
95
96impl std::fmt::Display for HandoffError {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        match self {
99            HandoffError::AgentNotFound(name) => {
100                write!(f, "Agent does not exist: {}", name)
101            }
102            HandoffError::ExecutionError(msg) => write!(f, "Agent execution error: {}", msg),
103            HandoffError::HandoffCycleDetected(name) => {
104                write!(f, "handoff cycle detected: {} already in the handoff chain, cyclic handoff rejected", name)
105            }
106            HandoffError::MaxHandoffDepthExceeded(depth) => {
107                write!(f, "handoff depth exceeded the limit: {}", depth)
108            }
109        }
110    }
111}
112
113impl std::error::Error for HandoffError {}