use adk_core::Content;
use serde::{Deserialize, Serialize};
use serde_json::Value;
pub const PENDING_STATE_KEY: &str = "codeact_pending";
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PendingToolCall {
pub call_id: u64,
pub tool: String,
pub args: Value,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ResolutionRecord {
Value(Value),
Raise(String),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum Disposition {
PendingResult,
Resolved(ResolutionRecord),
AwaitingConfirmation,
AwaitingCompletion {
#[serde(default, skip_serializing_if = "Option::is_none")]
pending_handle: Option<Value>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeActCheckpoint {
pub iteration: u32,
pub transcript: Vec<Content>,
pub snapshot: Vec<u8>,
pub call: PendingToolCall,
pub disposition: Disposition,
pub tool_roster: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn checkpoint_round_trips_through_json() {
let cp = CodeActCheckpoint {
iteration: 2,
transcript: vec![Content::new("user").with_text("hi")],
snapshot: vec![1, 2, 3],
call: PendingToolCall { call_id: 7, tool: "slow".into(), args: json!({"x": 1}) },
disposition: Disposition::AwaitingCompletion {
pending_handle: Some(json!({"task": "t1"})),
},
tool_roster: vec!["slow".into()],
};
let value = serde_json::to_value(&cp).unwrap();
let back: CodeActCheckpoint = serde_json::from_value(value.clone()).unwrap();
assert_eq!(value, serde_json::to_value(&back).unwrap());
}
#[test]
fn dispositions_round_trip() {
for case in [
Disposition::PendingResult,
Disposition::Resolved(ResolutionRecord::Value(json!(1))),
Disposition::Resolved(ResolutionRecord::Raise("boom".into())),
Disposition::AwaitingConfirmation,
Disposition::AwaitingCompletion { pending_handle: Some(json!("h")) },
Disposition::AwaitingCompletion { pending_handle: None },
] {
let v = serde_json::to_value(&case).unwrap();
assert_eq!(case, serde_json::from_value(v).unwrap());
}
}
}