crabtalk_core/agent/event.rs
1//! Agent event types for step-based execution and streaming.
2//!
3//! Two-level design:
4//! - [`AgentStep`]: data record of one LLM round (response + tool dispatch).
5//! - [`AgentEvent`]: fine-grained streaming enum for real-time UI updates.
6//! - [`AgentResponse`]: final result after a full agent run.
7//! - [`AgentStopReason`]: why the agent stopped.
8
9use crate::model::{Message, Response, ToolCall};
10
11/// A fine-grained event emitted during agent execution.
12///
13/// Yielded by `Agent::run_stream()` or emitted via `Hook::on_event()`
14/// for real-time status reporting to clients.
15#[derive(Debug, Clone)]
16pub enum AgentEvent {
17 /// Text content delta from the model.
18 TextDelta(String),
19 /// Thinking/reasoning content delta from the model.
20 ThinkingDelta(String),
21 /// Early notification: model is generating tool calls (names only, args incomplete).
22 ToolCallsBegin(Vec<ToolCall>),
23 /// Model is calling tools (with the complete tool calls).
24 ToolCallsStart(Vec<ToolCall>),
25 /// A single tool completed execution.
26 ToolResult {
27 /// The tool call ID this result belongs to.
28 call_id: String,
29 /// The output from the tool.
30 output: String,
31 /// Wall-clock duration of the tool dispatch in milliseconds.
32 duration_ms: u64,
33 },
34 /// All tools completed, continuing to next iteration.
35 ToolCallsComplete,
36 /// Context was compacted — carries the compaction summary.
37 Compact { summary: String },
38 /// Agent finished with final response.
39 Done(AgentResponse),
40}
41
42/// Data record of one LLM round (one model call + tool dispatch).
43#[derive(Debug, Clone)]
44pub struct AgentStep {
45 /// The model's response for this step.
46 pub response: Response,
47 /// Tool calls made in this step (if any).
48 pub tool_calls: Vec<ToolCall>,
49 /// Results from tool executions as messages.
50 pub tool_results: Vec<Message>,
51}
52
53/// Final response from a complete agent run.
54#[derive(Debug, Clone)]
55pub struct AgentResponse {
56 /// All steps taken during execution.
57 pub steps: Vec<AgentStep>,
58 /// Final text response (if any).
59 pub final_response: Option<String>,
60 /// Total number of iterations performed.
61 pub iterations: usize,
62 /// Why the agent stopped.
63 pub stop_reason: AgentStopReason,
64 /// The requested model name (from config, not the API-echoed value).
65 pub model: String,
66}
67
68/// Why the agent stopped executing.
69#[derive(Debug, Clone, PartialEq)]
70pub enum AgentStopReason {
71 /// Model produced a text response with no tool calls.
72 TextResponse,
73 /// Maximum iterations reached.
74 MaxIterations,
75 /// No tool calls and no text response.
76 NoAction,
77 /// Error during execution.
78 Error(String),
79}
80
81impl std::fmt::Display for AgentStopReason {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 match self {
84 Self::TextResponse => write!(f, "text_response"),
85 Self::MaxIterations => write!(f, "max_iterations"),
86 Self::NoAction => write!(f, "no_action"),
87 Self::Error(msg) => write!(f, "error: {msg}"),
88 }
89 }
90}