use serde::{Deserialize, Serialize};
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
use crate::typed_id::{AgentId, HarnessId, TurnId};
use super::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonStartedData {
pub harness_id: HarnessId,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_id: Option<AgentId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<ModelMetadata>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonCompletedData {
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_preview: Option<String>,
pub has_tool_calls: bool,
pub tool_call_count: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<TokenUsage>,
}
impl ReasonCompletedData {
pub fn success(
text: &str,
has_tool_calls: bool,
tool_call_count: u32,
duration_ms: Option<u64>,
usage: Option<TokenUsage>,
) -> Self {
let text_preview = if text.is_empty() {
None
} else {
Some(text.chars().take(200).collect())
};
Self {
success: true,
text_preview,
has_tool_calls,
tool_call_count,
error: None,
duration_ms,
usage,
}
}
pub fn failure(error: String, duration_ms: Option<u64>) -> Self {
Self {
success: false,
text_preview: None,
has_tool_calls: false,
tool_call_count: 0,
error: Some(error),
duration_ms,
usage: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "snake_case")]
pub enum RecoveryMode {
Finalize,
Restart,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonRecoveredData {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "turn_01933b5a00007000800000000000001"))]
pub turn_id: TurnId,
pub mode: RecoveryMode,
pub accumulated_len: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonThinkingStartedData {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "turn_01933b5a00007000800000000000001"))]
pub turn_id: TurnId,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonThinkingDeltaData {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "turn_01933b5a00007000800000000000001"))]
pub turn_id: TurnId,
pub delta: String,
pub accumulated: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonThinkingCompletedData {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "turn_01933b5a00007000800000000000001"))]
pub turn_id: TurnId,
pub thinking: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ReasonItemData {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "turn_01933b5a00007000800000000000001"))]
pub turn_id: TurnId,
pub provider: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
pub item_id: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub summary: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub token_count: Option<u32>,
}