use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum UserEvent {
#[serde(rename = "user.message")]
Message { content: Vec<ContentBlock> },
#[serde(rename = "user.interrupt")]
Interrupt {},
#[serde(rename = "user.custom_tool_result")]
CustomToolResult {
custom_tool_use_id: String,
content: Vec<ContentBlock>,
},
#[serde(rename = "user.tool_confirmation")]
ToolConfirmation {
tool_use_id: String,
result: String,
#[serde(skip_serializing_if = "Option::is_none")]
deny_message: Option<String>,
},
#[serde(rename = "user.define_outcome")]
DefineOutcome { criteria: String },
#[serde(rename = "user.tool_result")]
ToolResult { tool_use_id: String, content: Vec<ContentBlock> },
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum SessionEvent {
#[serde(rename = "agent.message")]
AgentMessage {
#[serde(default)]
content: serde_json::Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
},
#[serde(rename = "agent.tool_use")]
AgentToolUse {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
input: Option<serde_json::Value>,
},
#[serde(rename = "agent.custom_tool_use")]
AgentCustomToolUse {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
input: Option<serde_json::Value>,
},
#[serde(rename = "agent.mcp_tool_use")]
AgentMcpToolUse {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
server_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
input: Option<serde_json::Value>,
},
#[serde(rename = "session.status_idle")]
StatusIdle {
#[serde(default, skip_serializing_if = "Option::is_none")]
stop_reason: Option<serde_json::Value>,
},
#[serde(rename = "session.status_running")]
StatusRunning {},
#[serde(rename = "session.error")]
Error {
#[serde(default, skip_serializing_if = "Option::is_none")]
error: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
message: Option<String>,
},
#[serde(other)]
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ContentBlock {
Text { text: String },
}
impl ContentBlock {
pub fn text(text: impl Into<String>) -> Self {
Self::Text { text: text.into() }
}
}
impl UserEvent {
pub fn message(text: impl Into<String>) -> Self {
Self::Message { content: vec![ContentBlock::text(text)] }
}
pub fn custom_tool_result(
custom_tool_use_id: impl Into<String>,
result_text: impl Into<String>,
) -> Self {
Self::CustomToolResult {
custom_tool_use_id: custom_tool_use_id.into(),
content: vec![ContentBlock::text(result_text)],
}
}
pub fn allow_tool(tool_use_id: impl Into<String>) -> Self {
Self::ToolConfirmation {
tool_use_id: tool_use_id.into(),
result: "allow".to_string(),
deny_message: None,
}
}
pub fn deny_tool(tool_use_id: impl Into<String>, reason: impl Into<String>) -> Self {
Self::ToolConfirmation {
tool_use_id: tool_use_id.into(),
result: "deny".to_string(),
deny_message: Some(reason.into()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct SendEventsRequest {
pub events: Vec<UserEvent>,
}