use crate::runtime::tool_call::{PendingToolCall, Suspension, ToolCallResumeMode, ToolResult};
use crate::thread::ToolCall;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone)]
pub struct ToolGate {
pub id: String,
pub name: String,
pub args: Value,
pub result: Option<ToolResult>,
pub blocked: bool,
pub block_reason: Option<String>,
pub pending: bool,
pub suspend_ticket: Option<SuspendTicket>,
}
impl ToolGate {
pub fn new(id: impl Into<String>, name: impl Into<String>, args: Value) -> Self {
Self {
id: id.into(),
name: name.into(),
args,
result: None,
blocked: false,
block_reason: None,
pending: false,
suspend_ticket: None,
}
}
pub fn from_tool_call(call: &ToolCall) -> Self {
Self::new(&call.id, &call.name, call.arguments.clone())
}
pub fn is_blocked(&self) -> bool {
self.blocked
}
pub fn is_pending(&self) -> bool {
self.pending
}
pub fn idempotency_key(&self) -> &str {
&self.id
}
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct SuspendTicket {
#[serde(default)]
pub suspension: Suspension,
#[serde(default)]
pub pending: PendingToolCall,
#[serde(default)]
pub resume_mode: ToolCallResumeMode,
}
impl SuspendTicket {
pub fn new(
suspension: Suspension,
pending: PendingToolCall,
resume_mode: ToolCallResumeMode,
) -> Self {
Self {
suspension,
pending,
resume_mode,
}
}
pub fn use_decision_as_tool_result(suspension: Suspension, pending: PendingToolCall) -> Self {
Self::new(
suspension,
pending,
ToolCallResumeMode::UseDecisionAsToolResult,
)
}
pub fn with_resume_mode(mut self, resume_mode: ToolCallResumeMode) -> Self {
self.resume_mode = resume_mode;
self
}
pub fn with_pending(mut self, pending: PendingToolCall) -> Self {
self.pending = pending;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ToolCallAction {
Proceed,
Suspend(Box<SuspendTicket>),
Block { reason: String },
}
impl ToolCallAction {
pub fn suspend(ticket: SuspendTicket) -> Self {
Self::Suspend(Box::new(ticket))
}
}