lellm_graph/stream_chunk.rs
1//! StreamChunk — Data Plane 数据面事件。
2//!
3//! 高频、数据透传、无嵌套包装。
4//! 与控制面 RuntimeEvent 分离,避免高频数据事件撑爆控制事件通道。
5//!
6//! 设计原则:只承载"需要实时展示给用户的内容",不混入状态变更等低频数据。
7//! StreamChunk 携带 Execution View(展示内容),不是 Message。
8//! State 保存完整 Message。两者永不互相引用。
9
10use std::time::Duration;
11
12// ─── ToolPhase ────────────────────────────────────────────────
13
14/// 工具执行生命周期阶段。
15///
16/// 与 LangGraph (`on_tool_start`/`on_tool_end`)、
17/// OpenAI Agents SDK (`tool_call_started`/`tool_call_finished`)、
18/// Claude Desktop (`tool_use`/`tool_result`) 一致。
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum ToolPhase {
21 /// 工具已加入执行队列(尚未开始)
22 Queued,
23 /// 工具开始执行
24 Started,
25 /// 工具执行完成(成功或失败)
26 Finished,
27}
28
29// ─── StreamChunk ──────────────────────────────────────────────
30
31/// 数据面事件 — 高频、数据透传。
32///
33/// 统一流式协议,所有 Node(LLM、Tool、MCP、Workflow)共享。
34///
35/// **Tool 并发 emit 协议:**
36/// - Start 保证顺序 — 严格按照 ToolCall 顺序发射(A, B, C)
37/// - End 允许乱序 — 并发执行完成后按实际顺序发射(B, A, C),通过 call_id 关联
38#[derive(Debug, Clone)]
39pub enum StreamChunk {
40 /// 文本输出(LLM 生成的文本 token)
41 TextDelta(String),
42 /// 思考内容(LLM 的 reasoning/thinking block)
43 ///
44 /// `redacted` 为审查后的敏感推理内容(如 Anthropic thinking_redacted)。
45 /// Graph 层保留完整信息,UI 层决定是否展示。
46 ThinkingDelta {
47 text: String,
48 redacted: Option<String>,
49 },
50 /// 工具生命周期事件(Queued / Started / Finished)
51 ToolLifecycle {
52 phase: ToolPhase,
53 call_id: String,
54 tool_name: String,
55 },
56 /// 工具执行结果(展示用,content 为 String,前端直接展示)
57 ///
58 /// 与 State Plane 的 `Message::ToolResult` 分离。
59 /// State 保存完整 Message(含 content_blocks, metadata, raw_response)。
60 /// 此变体仅用于实时展示。
61 ToolOutput {
62 call_id: String,
63 tool_name: String,
64 content: String,
65 is_error: bool,
66 duration: Duration,
67 },
68}