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    ToolCall { state: ToolCallState },
69    /// 最终答案
70    FinalAnswer { content: String },
71    /// 流式执行错误
72    Error { message: String },
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn test_tool_call_state_accessors() {
81        let s = ToolCallState::Started {
82            tool_name: "calc".to_string(),
83            call_id: "call_1".to_string(),
84        };
85        assert_eq!(s.tool_name(), "calc");
86        assert_eq!(s.call_id(), "call_1");
87    }
88
89    #[test]
90    fn test_completed_state() {
91        let s = ToolCallState::Completed {
92            tool_name: "search".to_string(),
93            call_id: "call_2".to_string(),
94            result: "结果".to_string(),
95        };
96        assert_eq!(s.tool_name(), "search");
97        assert_eq!(s.call_id(), "call_2");
98    }
99
100    #[test]
101    fn test_agent_stream_event_text() {
102        let e = AgentStreamEvent::Text {
103            content: "hello".to_string(),
104        };
105        assert!(matches!(e, AgentStreamEvent::Text { .. }));
106    }
107
108    #[test]
109    fn test_agent_stream_event_final() {
110        let e = AgentStreamEvent::FinalAnswer {
111            content: "done".to_string(),
112        };
113        assert!(matches!(e, AgentStreamEvent::FinalAnswer { .. }));
114    }
115
116    #[test]
117    fn test_agent_stream_event_error() {
118        let e = AgentStreamEvent::Error {
119            message: "stream failed".to_string(),
120        };
121        assert!(matches!(e, AgentStreamEvent::Error { .. }));
122    }
123}