spec_ai/spec_ai_core/agent/
output.rs1use crate::spec_ai_core::agent::model::TokenUsage;
4use crate::spec_ai_core::agent::safety::SafetyStats;
5use crate::spec_ai_core::tools::ToolResult;
6use crate::spec_ai_core::types::MessageRole;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct AgentOutput {
13 pub response: String,
15 pub response_message_id: Option<i64>,
17 pub token_usage: Option<TokenUsage>,
19 pub tool_invocations: Vec<ToolInvocation>,
21 pub finish_reason: Option<String>,
23 pub recall_stats: Option<MemoryRecallStats>,
25 pub run_id: String,
27 pub next_action: Option<String>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub reasoning: Option<String>,
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub reasoning_summary: Option<String>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub graph_debug: Option<GraphDebugInfo>,
38 #[serde(default)]
40 pub safety: SafetyStats,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct GraphDebugNode {
46 pub id: i64,
47 pub node_type: String,
48 pub label: String,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct GraphDebugInfo {
54 pub enabled: bool,
55 pub graph_memory_enabled: bool,
56 pub auto_graph_enabled: bool,
57 pub graph_steering_enabled: bool,
58 pub node_count: usize,
59 pub edge_count: usize,
60 pub recent_nodes: Vec<GraphDebugNode>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct ToolInvocation {
66 pub name: String,
67 pub arguments: Value,
68 pub success: bool,
69 #[serde(skip_serializing_if = "Option::is_none")]
70 pub output: Option<String>,
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub error: Option<String>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77#[serde(tag = "type")]
78pub enum RunEvent {
79 #[serde(rename = "run.started")]
80 RunStarted { run_id: String, instruction: String },
81 #[serde(rename = "tool.call")]
82 ToolCall {
83 run_id: String,
84 tool_name: String,
85 arguments: Value,
86 },
87 #[serde(rename = "approval.requested")]
88 ApprovalRequested {
89 run_id: String,
90 tool_name: String,
91 arguments: Value,
92 mode: String,
93 },
94 #[serde(rename = "approval.decision")]
95 ApprovalDecision {
96 run_id: String,
97 tool_name: String,
98 approved: bool,
99 reason: String,
100 mode: String,
101 },
102 #[serde(rename = "tool.result")]
103 ToolResult {
104 run_id: String,
105 tool_name: String,
106 success: bool,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 output: Option<String>,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 error: Option<String>,
111 },
112 #[serde(rename = "message.final")]
113 MessageFinal {
114 run_id: String,
115 content: String,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 finish_reason: Option<String>,
118 },
119 #[serde(rename = "run.completed")]
120 RunCompleted {
121 run_id: String,
122 success: bool,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 finish_reason: Option<String>,
125 },
126 #[serde(rename = "error")]
127 Error {
128 #[serde(skip_serializing_if = "Option::is_none")]
129 run_id: Option<String>,
130 message: String,
131 },
132}
133
134impl ToolInvocation {
135 pub fn from_result(name: &str, arguments: Value, result: &ToolResult) -> Self {
136 let output = if result.output.trim().is_empty() {
137 None
138 } else {
139 Some(result.output.clone())
140 };
141
142 Self {
143 name: name.to_string(),
144 arguments,
145 success: result.success,
146 output,
147 error: result.error.clone(),
148 }
149 }
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct MemoryRecallStats {
155 pub strategy: MemoryRecallStrategy,
156 pub matches: Vec<MemoryRecallMatch>,
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub enum MemoryRecallStrategy {
162 Semantic { requested: usize, returned: usize },
163 RecentContext { limit: usize },
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct MemoryRecallMatch {
169 pub message_id: Option<i64>,
170 pub score: f32,
171 pub role: MessageRole,
172 pub preview: String,
173}