use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(from = "ToolCallRecordWire")]
pub struct ToolCallRecord {
pub tool_name: String,
pub tool_use_id: String,
pub args_hash: String,
pub result: String,
pub status: ToolCallRecordStatus,
pub duration_ms: Option<u64>,
pub iteration: usize,
pub timestamp: String,
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum ToolCallRecordStatus {
#[default]
Open,
Completed,
Failed,
Rejected,
}
impl ToolCallRecordStatus {
pub(crate) fn terminal(wire: &str) -> Option<Self> {
match wire {
"completed" => Some(Self::Completed),
"failed" => Some(Self::Failed),
"rejected" => Some(Self::Rejected),
_ => None,
}
}
pub fn is_rejected(self) -> bool {
self == Self::Rejected
}
}
#[derive(Default, Deserialize)]
#[serde(default)]
struct ToolCallRecordWire {
tool_name: String,
tool_use_id: String,
args_hash: String,
result: String,
status: Option<ToolCallRecordStatus>,
is_rejected: bool,
duration_ms: Option<u64>,
iteration: usize,
timestamp: String,
}
impl From<ToolCallRecordWire> for ToolCallRecord {
fn from(wire: ToolCallRecordWire) -> Self {
Self {
tool_name: wire.tool_name,
tool_use_id: wire.tool_use_id,
args_hash: wire.args_hash,
result: wire.result,
status: wire.status.unwrap_or(if wire.is_rejected {
ToolCallRecordStatus::Rejected
} else {
ToolCallRecordStatus::Open
}),
duration_ms: wire.duration_ms,
iteration: wire.iteration,
timestamp: wire.timestamp,
}
}
}