use serde::{Deserialize, Serialize};
pub const RPC_PROTOCOL_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RpcAttachment {
pub path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mime: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TurnUsage {
pub input_tokens: u64,
pub output_tokens: u64,
#[serde(default)]
pub cache_read_input_tokens: u64,
#[serde(default)]
pub cache_creation_input_tokens: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub enum RpcCommand {
#[serde(rename = "prompt")]
Prompt {
id: String,
message: String,
#[serde(default)]
attachments: Vec<RpcAttachment>,
},
#[serde(rename = "follow_up")]
FollowUp {
id: String,
message: String,
},
#[serde(rename = "compact")]
Compact {
id: String,
},
#[serde(rename = "new_session")]
NewSession {
id: String,
},
#[serde(rename = "get_messages")]
GetMessages {
id: String,
},
#[serde(rename = "set_model")]
SetModel {
id: String,
model: String,
},
#[serde(rename = "get_available_models")]
GetAvailableModels {
id: String,
},
#[serde(rename = "abort")]
Abort {
id: String,
},
#[serde(rename = "get_session_stats")]
GetSessionStats {
id: String,
},
#[serde(rename = "get_state")]
GetState {
id: String,
},
#[serde(rename = "shutdown")]
Shutdown,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub enum RpcEvent {
#[serde(rename = "message_update")]
MessageUpdate {
event: AssistantEvent,
},
#[serde(rename = "subagent_start")]
SubagentStart {
subagent_id: u64,
agent_name: String,
task_preview: String,
},
#[serde(rename = "subagent_update")]
SubagentUpdate {
subagent_id: u64,
agent_name: String,
status: String,
},
#[serde(rename = "subagent_done")]
SubagentDone {
subagent_id: u64,
agent_name: String,
result_preview: String,
duration_secs: f64,
},
#[serde(rename = "agent_end")]
AgentEnd {
usage: TurnUsage,
},
#[serde(rename = "response")]
Response {
id: String,
command: String,
#[serde(flatten)]
body: serde_json::Value,
},
#[serde(rename = "error")]
Error {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
message: String,
},
#[serde(rename = "ready")]
Ready {
session_id: String,
model: String,
protocol_version: u32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub enum AssistantEvent {
#[serde(rename = "text_delta")]
TextDelta {
delta: String,
},
#[serde(rename = "thinking_delta")]
ThinkingDelta {
delta: String,
},
#[serde(rename = "toolcall_start")]
ToolcallStart {
tool_id: String,
tool_name: String,
},
#[serde(rename = "toolcall_input_delta")]
ToolcallInputDelta {
tool_id: String,
delta: String,
},
#[serde(rename = "toolcall_input")]
ToolcallInput {
tool_id: String,
input: serde_json::Value,
},
#[serde(rename = "toolcall_result")]
ToolcallResult {
tool_id: String,
result: String,
},
}