use crate::event::AgentEvent;
pub const SDK_SCHEMA_VERSION: u32 = 2;
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(tag = "type")]
pub enum SdkCommand {
prompt {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
message: String,
},
#[serde(rename = "continue")]
continue_ {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
message: String,
},
steer {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
message: String,
},
follow_up {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
message: String,
},
abort {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
},
set_model {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
model: String,
},
set_thinking_level {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
level: String,
},
compact {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
},
session_info {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
},
quit {
#[serde(default, skip_serializing_if = "Option::is_none")]
id: Option<String>,
},
}
impl SdkCommand {
pub fn id(&self) -> Option<&str> {
match self {
Self::prompt { id, .. }
| Self::continue_ { id, .. }
| Self::steer { id, .. }
| Self::follow_up { id, .. }
| Self::abort { id }
| Self::set_model { id, .. }
| Self::set_thinking_level { id, .. }
| Self::compact { id }
| Self::session_info { id }
| Self::quit { id } => id.as_deref(),
}
}
pub fn command_name(&self) -> &'static str {
match self {
Self::prompt { .. } => "prompt",
Self::continue_ { .. } => "continue",
Self::steer { .. } => "steer",
Self::follow_up { .. } => "follow_up",
Self::abort { .. } => "abort",
Self::set_model { .. } => "set_model",
Self::set_thinking_level { .. } => "set_thinking_level",
Self::compact { .. } => "compact",
Self::session_info { .. } => "session_info",
Self::quit { .. } => "quit",
}
}
pub fn is_quit(&self) -> bool {
matches!(self, Self::quit { .. })
}
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct SdkResponse {
#[serde(default = "response_type")]
r#type: String,
pub command: String,
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}
impl SdkResponse {
pub fn success(id: Option<&str>, command: &str) -> Self {
Self {
r#type: response_type(),
command: command.to_owned(),
success: true,
id: id.map(|s| s.to_owned()),
error: None,
data: None,
}
}
pub fn success_with_data(id: Option<&str>, command: &str, data: serde_json::Value) -> Self {
Self {
r#type: response_type(),
command: command.to_owned(),
success: true,
id: id.map(|s| s.to_owned()),
error: None,
data: Some(data),
}
}
pub fn error(id: Option<&str>, command: &str, message: &str) -> Self {
Self {
r#type: response_type(),
command: command.to_owned(),
success: false,
id: id.map(|s| s.to_owned()),
error: Some(message.to_owned()),
data: None,
}
}
}
fn response_type() -> String {
"response".to_owned()
}
pub fn agent_event_to_value(event: &AgentEvent) -> serde_json::Value {
match serde_json::to_value(event) {
Ok(v) => v,
Err(_) => serde_json::json!({
"type": "SdkSerializationError",
"message": "failed to serialize agent event",
}),
}
}