use crate::spec_ai_core::agent::model::TokenUsage;
use crate::spec_ai_core::tools::ToolResult;
use crate::spec_ai_core::types::MessageRole;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentOutput {
pub response: String,
pub response_message_id: Option<i64>,
pub token_usage: Option<TokenUsage>,
pub tool_invocations: Vec<ToolInvocation>,
pub finish_reason: Option<String>,
pub recall_stats: Option<MemoryRecallStats>,
pub run_id: String,
pub next_action: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_summary: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub graph_debug: Option<GraphDebugInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphDebugNode {
pub id: i64,
pub node_type: String,
pub label: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphDebugInfo {
pub enabled: bool,
pub graph_memory_enabled: bool,
pub auto_graph_enabled: bool,
pub graph_steering_enabled: bool,
pub node_count: usize,
pub edge_count: usize,
pub recent_nodes: Vec<GraphDebugNode>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolInvocation {
pub name: String,
pub arguments: Value,
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub output: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl ToolInvocation {
pub fn from_result(name: &str, arguments: Value, result: &ToolResult) -> Self {
let output = if result.output.trim().is_empty() {
None
} else {
Some(result.output.clone())
};
Self {
name: name.to_string(),
arguments,
success: result.success,
output,
error: result.error.clone(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryRecallStats {
pub strategy: MemoryRecallStrategy,
pub matches: Vec<MemoryRecallMatch>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MemoryRecallStrategy {
Semantic { requested: usize, returned: usize },
RecentContext { limit: usize },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryRecallMatch {
pub message_id: Option<i64>,
pub score: f32,
pub role: MessageRole,
pub preview: String,
}