Skip to main content

lc_agents/streaming/
state.rs

1//! 流式工具调用状态与事件
2
3use serde_json::Value;
4
5/// 工具调用流状态
6#[derive(Debug, Clone)]
7pub enum ToolCallState {
8    /// 工具调用开始
9    Started { tool_name: String, call_id: String },
10    /// 参数正在流式传输
11    ArgumentsStreaming {
12        tool_name: String,
13        call_id: String,
14        partial_args: String,
15    },
16    /// 参数完成,准备执行
17    ArgumentsComplete {
18        tool_name: String,
19        call_id: String,
20        args: Value,
21    },
22    /// 工具正在执行
23    Executing { tool_name: String, call_id: String },
24    /// 执行完成
25    Completed {
26        tool_name: String,
27        call_id: String,
28        result: String,
29    },
30    /// 执行失败
31    Failed {
32        tool_name: String,
33        call_id: String,
34        error: String,
35    },
36}
37
38impl ToolCallState {
39    pub fn tool_name(&self) -> &str {
40        match self {
41            ToolCallState::Started { tool_name, .. }
42            | ToolCallState::ArgumentsStreaming { tool_name, .. }
43            | ToolCallState::ArgumentsComplete { tool_name, .. }
44            | ToolCallState::Executing { tool_name, .. }
45            | ToolCallState::Completed { tool_name, .. }
46            | ToolCallState::Failed { tool_name, .. } => tool_name,
47        }
48    }
49
50    pub fn call_id(&self) -> &str {
51        match self {
52            ToolCallState::Started { call_id, .. }
53            | ToolCallState::ArgumentsStreaming { call_id, .. }
54            | ToolCallState::ArgumentsComplete { call_id, .. }
55            | ToolCallState::Executing { call_id, .. }
56            | ToolCallState::Completed { call_id, .. }
57            | ToolCallState::Failed { call_id, .. } => call_id,
58        }
59    }
60}
61
62/// Agent 流式事件
63#[derive(Debug, Clone)]
64pub enum AgentStreamEvent {
65    /// LLM 输出文本(token)
66    Text { content: String },
67
68    /// 工具调用状态变化 (Function Calling 风格)
69    ToolCall { state: ToolCallState },
70
71    /// ReAct 风格工具调用开始
72    ToolStart { name: String, input: String },
73
74    /// ReAct 风格工具调用完成
75    ToolEnd { name: String, output: String },
76
77    /// 最终答案
78    FinalAnswer { content: String },
79
80    /// 流式执行错误
81    Error { message: String },
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_tool_call_state_accessors() {
90        let s = ToolCallState::Started {
91            tool_name: "calc".to_string(),
92            call_id: "call_1".to_string(),
93        };
94        assert_eq!(s.tool_name(), "calc");
95        assert_eq!(s.call_id(), "call_1");
96    }
97
98    #[test]
99    fn test_completed_state() {
100        let s = ToolCallState::Completed {
101            tool_name: "search".to_string(),
102            call_id: "call_2".to_string(),
103            result: "结果".to_string(),
104        };
105        assert_eq!(s.tool_name(), "search");
106        assert_eq!(s.call_id(), "call_2");
107    }
108
109    #[test]
110    fn test_agent_stream_event_text() {
111        let e = AgentStreamEvent::Text {
112            content: "hello".to_string(),
113        };
114        assert!(matches!(e, AgentStreamEvent::Text { .. }));
115    }
116
117    #[test]
118    fn test_agent_stream_event_final() {
119        let e = AgentStreamEvent::FinalAnswer {
120            content: "done".to_string(),
121        };
122        assert!(matches!(e, AgentStreamEvent::FinalAnswer { .. }));
123    }
124
125    #[test]
126    fn test_agent_stream_event_error() {
127        let e = AgentStreamEvent::Error {
128            message: "stream failed".to_string(),
129        };
130        assert!(matches!(e, AgentStreamEvent::Error { .. }));
131    }
132}