diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 0ecada0fb3..c700a2dd1c 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -861,9 +861,11 @@ name = "codex-app-server-protocol" version = "0.0.0" dependencies = [ "anyhow", + "clap", "codex-protocol", "paste", "pretty_assertions", + "schemars 0.8.22", "serde", "serde_json", "strum_macros 0.27.2", @@ -1332,6 +1334,7 @@ dependencies = [ "icu_locale_core", "mcp-types", "mime_guess", + "schemars 0.8.22", "serde", "serde_json", "serde_with", @@ -3579,6 +3582,7 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" name = "mcp-types" version = "0.0.0" dependencies = [ + "schemars 0.8.22", "serde", "serde_json", "ts-rs", diff --git a/codex-rs/app-server-protocol/Cargo.toml b/codex-rs/app-server-protocol/Cargo.toml index b18028fbe4..58b0b9d607 100644 --- a/codex-rs/app-server-protocol/Cargo.toml +++ b/codex-rs/app-server-protocol/Cargo.toml @@ -11,8 +11,11 @@ path = "src/lib.rs" workspace = true [dependencies] +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } codex-protocol = { workspace = true } paste = { workspace = true } +schemars = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } strum_macros = { workspace = true } diff --git a/codex-rs/app-server-protocol/src/bin/export.rs b/codex-rs/app-server-protocol/src/bin/export.rs new file mode 100644 index 0000000000..d029ecbffa --- /dev/null +++ b/codex-rs/app-server-protocol/src/bin/export.rs @@ -0,0 +1,22 @@ +use anyhow::Result; +use clap::Parser; +use std::path::PathBuf; + +#[derive(Parser, Debug)] +#[command( + about = "Generate TypeScript bindings and JSON Schemas for the Codex app-server protocol" +)] +struct Args { + /// Output directory where generated files will be written + #[arg(short = 'o', long = "out", value_name = "DIR")] + out_dir: PathBuf, + + /// Optional Prettier executable path to format generated TypeScript files + #[arg(short = 'p', long = "prettier", value_name = "PRETTIER_BIN")] + prettier: Option, +} + +fn main() -> Result<()> { + let args = Args::parse(); + codex_app_server_protocol::generate_types(&args.out_dir, args.prettier.as_deref()) +} diff --git a/codex-rs/app-server-protocol/src/export.rs b/codex-rs/app-server-protocol/src/export.rs new file mode 100644 index 0000000000..21ba3facc4 --- /dev/null +++ b/codex-rs/app-server-protocol/src/export.rs @@ -0,0 +1,404 @@ +use crate::ClientNotification; +use crate::ClientRequest; +use crate::ServerNotification; +use crate::ServerRequest; +use crate::export_client_response_schemas; +use crate::export_client_responses; +use crate::export_server_response_schemas; +use crate::export_server_responses; +use anyhow::Context; +use anyhow::Result; +use anyhow::anyhow; +use schemars::JsonSchema; +use schemars::schema::RootSchema; +use schemars::schema_for; +use serde::Serialize; +use serde_json::Map; +use serde_json::Value; +use std::collections::BTreeMap; +use std::ffi::OsStr; +use std::fs; +use std::io::Read; +use std::io::Write; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; +use ts_rs::TS; + +const HEADER: &str = "// GENERATED CODE! DO NOT MODIFY BY HAND!\n\n"; + +macro_rules! for_each_schema_type { + ($macro:ident) => { + $macro!(crate::RequestId); + $macro!(crate::JSONRPCMessage); + $macro!(crate::JSONRPCRequest); + $macro!(crate::JSONRPCNotification); + $macro!(crate::JSONRPCResponse); + $macro!(crate::JSONRPCError); + $macro!(crate::JSONRPCErrorError); + $macro!(crate::AddConversationListenerParams); + $macro!(crate::AddConversationSubscriptionResponse); + $macro!(crate::ApplyPatchApprovalParams); + $macro!(crate::ApplyPatchApprovalResponse); + $macro!(crate::ArchiveConversationParams); + $macro!(crate::ArchiveConversationResponse); + $macro!(crate::AuthMode); + $macro!(crate::AuthStatusChangeNotification); + $macro!(crate::CancelLoginChatGptParams); + $macro!(crate::CancelLoginChatGptResponse); + $macro!(crate::ClientInfo); + $macro!(crate::ClientNotification); + $macro!(crate::ClientRequest); + $macro!(crate::ConversationSummary); + $macro!(crate::ExecCommandApprovalParams); + $macro!(crate::ExecCommandApprovalResponse); + $macro!(crate::ExecOneOffCommandParams); + $macro!(crate::ExecOneOffCommandResponse); + $macro!(crate::FuzzyFileSearchParams); + $macro!(crate::FuzzyFileSearchResponse); + $macro!(crate::FuzzyFileSearchResult); + $macro!(crate::GetAuthStatusParams); + $macro!(crate::GetAuthStatusResponse); + $macro!(crate::GetUserAgentResponse); + $macro!(crate::GetUserSavedConfigResponse); + $macro!(crate::GitDiffToRemoteParams); + $macro!(crate::GitDiffToRemoteResponse); + $macro!(crate::GitSha); + $macro!(crate::InitializeParams); + $macro!(crate::InitializeResponse); + $macro!(crate::InputItem); + $macro!(crate::InterruptConversationParams); + $macro!(crate::InterruptConversationResponse); + $macro!(crate::ListConversationsParams); + $macro!(crate::ListConversationsResponse); + $macro!(crate::LoginApiKeyParams); + $macro!(crate::LoginApiKeyResponse); + $macro!(crate::LoginChatGptCompleteNotification); + $macro!(crate::LoginChatGptResponse); + $macro!(crate::LogoutChatGptParams); + $macro!(crate::LogoutChatGptResponse); + $macro!(crate::NewConversationParams); + $macro!(crate::NewConversationResponse); + $macro!(crate::Profile); + $macro!(crate::RemoveConversationListenerParams); + $macro!(crate::RemoveConversationSubscriptionResponse); + $macro!(crate::ResumeConversationParams); + $macro!(crate::ResumeConversationResponse); + $macro!(crate::SandboxSettings); + $macro!(crate::SendUserMessageParams); + $macro!(crate::SendUserMessageResponse); + $macro!(crate::SendUserTurnParams); + $macro!(crate::SendUserTurnResponse); + $macro!(crate::ServerNotification); + $macro!(crate::ServerRequest); + $macro!(crate::SessionConfiguredNotification); + $macro!(crate::SetDefaultModelParams); + $macro!(crate::SetDefaultModelResponse); + $macro!(crate::Tools); + $macro!(crate::UserInfoResponse); + $macro!(crate::UserSavedConfig); + $macro!(codex_protocol::protocol::EventMsg); + $macro!(codex_protocol::protocol::FileChange); + $macro!(codex_protocol::parse_command::ParsedCommand); + $macro!(codex_protocol::protocol::SandboxPolicy); + }; +} + +pub fn generate_types(out_dir: &Path, prettier: Option<&Path>) -> Result<()> { + generate_ts(out_dir, prettier)?; + generate_json(out_dir)?; + Ok(()) +} + +pub fn generate_ts(out_dir: &Path, prettier: Option<&Path>) -> Result<()> { + ensure_dir(out_dir)?; + + ClientRequest::export_all_to(out_dir)?; + export_client_responses(out_dir)?; + ClientNotification::export_all_to(out_dir)?; + + ServerRequest::export_all_to(out_dir)?; + export_server_responses(out_dir)?; + ServerNotification::export_all_to(out_dir)?; + + generate_index_ts(out_dir)?; + + let ts_files = ts_files_in(out_dir)?; + for file in &ts_files { + prepend_header_if_missing(file)?; + } + + if let Some(prettier_bin) = prettier + && !ts_files.is_empty() + { + let status = Command::new(prettier_bin) + .arg("--write") + .args(ts_files.iter().map(|p| p.as_os_str())) + .status() + .with_context(|| format!("Failed to invoke Prettier at {}", prettier_bin.display()))?; + if !status.success() { + return Err(anyhow!("Prettier failed with status {status}")); + } + } + + Ok(()) +} + +pub fn generate_json(out_dir: &Path) -> Result<()> { + ensure_dir(out_dir)?; + let mut bundle: BTreeMap = BTreeMap::new(); + + macro_rules! add_schema { + ($ty:path) => {{ + let name = type_basename(stringify!($ty)); + let schema = write_json_schema_with_return::<$ty>(out_dir, &name)?; + bundle.insert(name, schema); + }}; + } + + for_each_schema_type!(add_schema); + + export_client_response_schemas(out_dir)?; + export_server_response_schemas(out_dir)?; + + let mut definitions = Map::new(); + + const SPECIAL_DEFINITIONS: &[&str] = &[ + "ClientNotification", + "ClientRequest", + "EventMsg", + "FileChange", + "InputItem", + "ParsedCommand", + "SandboxPolicy", + "ServerNotification", + "ServerRequest", + ]; + + for (name, schema) in bundle { + let mut schema_value = serde_json::to_value(schema)?; + if let Value::Object(ref mut obj) = schema_value { + if let Some(defs) = obj.remove("definitions") + && let Value::Object(defs_obj) = defs + { + for (def_name, def_schema) in defs_obj { + if !SPECIAL_DEFINITIONS.contains(&def_name.as_str()) { + definitions.insert(def_name, def_schema); + } + } + } + + if let Some(Value::Array(one_of)) = obj.get_mut("oneOf") { + for variant in one_of.iter_mut() { + if let Some(variant_name) = variant_definition_name(&name, variant) + && let Value::Object(variant_obj) = variant + { + variant_obj.insert("title".into(), Value::String(variant_name)); + } + } + } + } + definitions.insert(name, schema_value); + } + + let mut root = Map::new(); + root.insert( + "$schema".to_string(), + Value::String("http://json-schema.org/draft-07/schema#".into()), + ); + root.insert( + "title".to_string(), + Value::String("CodexAppServerProtocol".into()), + ); + root.insert("type".to_string(), Value::String("object".into())); + root.insert("definitions".to_string(), Value::Object(definitions)); + + write_pretty_json( + out_dir.join("codex_app_server_protocol.schemas.json"), + &Value::Object(root), + )?; + + Ok(()) +} + +fn write_json_schema_with_return(out_dir: &Path, name: &str) -> Result +where + T: JsonSchema, +{ + let file_stem = name.trim(); + let schema = schema_for!(T); + write_pretty_json(out_dir.join(format!("{file_stem}.json")), &schema) + .with_context(|| format!("Failed to write JSON schema for {file_stem}"))?; + Ok(schema) +} + +pub(crate) fn write_json_schema(out_dir: &Path, name: &str) -> Result<()> +where + T: JsonSchema, +{ + write_json_schema_with_return::(out_dir, name).map(|_| ()) +} + +fn write_pretty_json(path: PathBuf, value: &impl Serialize) -> Result<()> { + let json = serde_json::to_vec_pretty(value) + .with_context(|| format!("Failed to serialize JSON schema to {}", path.display()))?; + fs::write(&path, json).with_context(|| format!("Failed to write {}", path.display()))?; + Ok(()) +} +fn type_basename(type_path: &str) -> String { + type_path + .rsplit_once("::") + .map(|(_, name)| name) + .unwrap_or(type_path) + .trim() + .to_string() +} + +fn variant_definition_name(base: &str, variant: &Value) -> Option { + if let Some(props) = variant.get("properties").and_then(Value::as_object) { + if let Some(method_literal) = literal_from_property(props, "method") { + let pascal = to_pascal_case(method_literal); + return Some(match base { + "ClientRequest" | "ServerRequest" => format!("{pascal}Request"), + "ClientNotification" | "ServerNotification" => format!("{pascal}Notification"), + _ => format!("{pascal}{base}"), + }); + } + + if let Some(type_literal) = literal_from_property(props, "type") { + let pascal = to_pascal_case(type_literal); + return Some(match base { + "EventMsg" => format!("{pascal}EventMsg"), + _ => format!("{pascal}{base}"), + }); + } + + if let Some(mode_literal) = literal_from_property(props, "mode") { + let pascal = to_pascal_case(mode_literal); + return Some(match base { + "SandboxPolicy" => format!("{pascal}SandboxPolicy"), + _ => format!("{pascal}{base}"), + }); + } + + if props.len() == 1 + && let Some(key) = props.keys().next() + { + let pascal = to_pascal_case(key); + return Some(format!("{pascal}{base}")); + } + } + + if let Some(required) = variant.get("required").and_then(Value::as_array) + && required.len() == 1 + && let Some(key) = required[0].as_str() + { + let pascal = to_pascal_case(key); + return Some(format!("{pascal}{base}")); + } + + None +} + +fn literal_from_property<'a>(props: &'a Map, key: &str) -> Option<&'a str> { + props + .get(key) + .and_then(|value| value.get("enum")) + .and_then(Value::as_array) + .and_then(|arr| arr.first()) + .and_then(Value::as_str) +} + +fn to_pascal_case(input: &str) -> String { + let mut result = String::new(); + let mut capitalize_next = true; + + for c in input.chars() { + if c == '_' || c == '-' { + capitalize_next = true; + continue; + } + + if capitalize_next { + result.extend(c.to_uppercase()); + capitalize_next = false; + } else { + result.push(c); + } + } + + result +} + +fn ensure_dir(dir: &Path) -> Result<()> { + fs::create_dir_all(dir) + .with_context(|| format!("Failed to create output directory {}", dir.display())) +} + +fn prepend_header_if_missing(path: &Path) -> Result<()> { + let mut content = String::new(); + { + let mut f = fs::File::open(path) + .with_context(|| format!("Failed to open {} for reading", path.display()))?; + f.read_to_string(&mut content) + .with_context(|| format!("Failed to read {}", path.display()))?; + } + + if content.starts_with(HEADER) { + return Ok(()); + } + + let mut f = fs::File::create(path) + .with_context(|| format!("Failed to open {} for writing", path.display()))?; + f.write_all(HEADER.as_bytes()) + .with_context(|| format!("Failed to write header to {}", path.display()))?; + f.write_all(content.as_bytes()) + .with_context(|| format!("Failed to write content to {}", path.display()))?; + Ok(()) +} + +fn ts_files_in(dir: &Path) -> Result> { + let mut files = Vec::new(); + for entry in + fs::read_dir(dir).with_context(|| format!("Failed to read dir {}", dir.display()))? + { + let entry = entry?; + let path = entry.path(); + if path.is_file() && path.extension() == Some(OsStr::new("ts")) { + files.push(path); + } + } + files.sort(); + Ok(files) +} + +fn generate_index_ts(out_dir: &Path) -> Result { + let mut entries: Vec = Vec::new(); + let mut stems: Vec = ts_files_in(out_dir)? + .into_iter() + .filter_map(|p| { + let stem = p.file_stem()?.to_string_lossy().into_owned(); + if stem == "index" { None } else { Some(stem) } + }) + .collect(); + stems.sort(); + stems.dedup(); + + for name in stems { + entries.push(format!("export type {{ {name} }} from \"./{name}\";\n")); + } + + let mut content = + String::with_capacity(HEADER.len() + entries.iter().map(String::len).sum::()); + content.push_str(HEADER); + for line in &entries { + content.push_str(line); + } + + let index_path = out_dir.join("index.ts"); + let mut f = fs::File::create(&index_path) + .with_context(|| format!("Failed to create {}", index_path.display()))?; + f.write_all(content.as_bytes()) + .with_context(|| format!("Failed to write {}", index_path.display()))?; + Ok(index_path) +} diff --git a/codex-rs/app-server-protocol/src/jsonrpc_lite.rs b/codex-rs/app-server-protocol/src/jsonrpc_lite.rs index 9d6d6da06f..c0b88b0215 100644 --- a/codex-rs/app-server-protocol/src/jsonrpc_lite.rs +++ b/codex-rs/app-server-protocol/src/jsonrpc_lite.rs @@ -1,13 +1,14 @@ //! We do not do true JSON-RPC 2.0, as we neither send nor expect the //! "jsonrpc": "2.0" field. +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use ts_rs::TS; pub const JSONRPC_VERSION: &str = "2.0"; -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, JsonSchema, TS)] #[serde(untagged)] pub enum RequestId { String(String), @@ -18,7 +19,7 @@ pub enum RequestId { pub type Result = serde_json::Value; /// Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum JSONRPCMessage { Request(JSONRPCRequest), @@ -28,7 +29,7 @@ pub enum JSONRPCMessage { } /// A request that expects a response. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCRequest { pub id: RequestId, pub method: String, @@ -37,7 +38,7 @@ pub struct JSONRPCRequest { } /// A notification which does not expect a response. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCNotification { pub method: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -45,20 +46,20 @@ pub struct JSONRPCNotification { } /// A successful (non-error) response to a request. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCResponse { pub id: RequestId, pub result: Result, } /// A response to a request that indicates an error occurred. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCError { pub error: JSONRPCErrorError, pub id: RequestId, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCErrorError { pub code: i64, #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/codex-rs/app-server-protocol/src/lib.rs b/codex-rs/app-server-protocol/src/lib.rs index 517702bbd8..cc2310bc85 100644 --- a/codex-rs/app-server-protocol/src/lib.rs +++ b/codex-rs/app-server-protocol/src/lib.rs @@ -1,5 +1,9 @@ +mod export; mod jsonrpc_lite; mod protocol; +pub use export::generate_json; +pub use export::generate_ts; +pub use export::generate_types; pub use jsonrpc_lite::*; pub use protocol::*; diff --git a/codex-rs/app-server-protocol/src/protocol.rs b/codex-rs/app-server-protocol/src/protocol.rs index 63b11829cd..9c10d23360 100644 --- a/codex-rs/app-server-protocol/src/protocol.rs +++ b/codex-rs/app-server-protocol/src/protocol.rs @@ -18,13 +18,14 @@ use codex_protocol::protocol::ReviewDecision; use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::TurnAbortReason; use paste::paste; +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use strum_macros::Display; use ts_rs::TS; use uuid::Uuid; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, TS)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, TS)] #[ts(type = "string")] pub struct GitSha(pub String); @@ -34,7 +35,7 @@ impl GitSha { } } -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Display, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Display, JsonSchema, TS)] #[serde(rename_all = "lowercase")] pub enum AuthMode { ApiKey, @@ -56,7 +57,7 @@ macro_rules! client_request_definitions { ),* $(,)? ) => { /// Request from the client to the server. - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(tag = "method", rename_all = "camelCase")] pub enum ClientRequest { $( @@ -78,6 +79,15 @@ macro_rules! client_request_definitions { )* Ok(()) } + + pub fn export_client_response_schemas( + out_dir: &::std::path::Path, + ) -> ::anyhow::Result<()> { + $( + crate::export::write_json_schema::<$response>(out_dir, stringify!($response))?; + )* + Ok(()) + } }; } @@ -175,13 +185,13 @@ client_request_definitions! { }, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct InitializeParams { pub client_info: ClientInfo, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ClientInfo { pub name: String, @@ -190,13 +200,13 @@ pub struct ClientInfo { pub version: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct InitializeResponse { pub user_agent: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct NewConversationParams { /// Optional override for the model name (e.g. "o3", "o4-mini"). @@ -239,7 +249,7 @@ pub struct NewConversationParams { pub include_apply_patch_tool: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct NewConversationResponse { pub conversation_id: ConversationId, @@ -250,7 +260,7 @@ pub struct NewConversationResponse { pub rollout_path: PathBuf, } -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ResumeConversationResponse { pub conversation_id: ConversationId, @@ -259,7 +269,7 @@ pub struct ResumeConversationResponse { pub initial_messages: Option>, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ListConversationsParams { /// Optional page size; defaults to a reasonable server-side value. @@ -270,7 +280,7 @@ pub struct ListConversationsParams { pub cursor: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ConversationSummary { pub conversation_id: ConversationId, @@ -281,7 +291,7 @@ pub struct ConversationSummary { pub timestamp: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ListConversationsResponse { pub items: Vec, @@ -291,7 +301,7 @@ pub struct ListConversationsResponse { pub next_cursor: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ResumeConversationParams { /// Absolute path to the rollout JSONL file. @@ -301,78 +311,81 @@ pub struct ResumeConversationParams { pub overrides: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct AddConversationSubscriptionResponse { + #[schemars(with = "String")] pub subscription_id: Uuid, } /// The [`ConversationId`] must match the `rollout_path`. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ArchiveConversationParams { pub conversation_id: ConversationId, pub rollout_path: PathBuf, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ArchiveConversationResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct RemoveConversationSubscriptionResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct LoginApiKeyParams { pub api_key: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct LoginApiKeyResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct LoginChatGptResponse { + #[schemars(with = "String")] pub login_id: Uuid, /// URL the client should open in a browser to initiate the OAuth flow. pub auth_url: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct GitDiffToRemoteResponse { pub sha: GitSha, pub diff: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct CancelLoginChatGptParams { + #[schemars(with = "String")] pub login_id: Uuid, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct GitDiffToRemoteParams { pub cwd: PathBuf, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct CancelLoginChatGptResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct LogoutChatGptParams {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct LogoutChatGptResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct GetAuthStatusParams { /// If true, include the current auth token (if available) in the response. @@ -383,7 +396,7 @@ pub struct GetAuthStatusParams { pub refresh_token: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ExecOneOffCommandParams { /// Command argv to execute. @@ -399,7 +412,7 @@ pub struct ExecOneOffCommandParams { pub sandbox_policy: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ExecOneOffCommandResponse { pub exit_code: i32, @@ -407,7 +420,7 @@ pub struct ExecOneOffCommandResponse { pub stderr: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct GetAuthStatusResponse { #[serde(skip_serializing_if = "Option::is_none")] @@ -422,13 +435,13 @@ pub struct GetAuthStatusResponse { pub requires_openai_auth: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct GetUserAgentResponse { pub user_agent: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct UserInfoResponse { /// Note: `alleged_user_email` is not currently verified. We read it from @@ -438,13 +451,13 @@ pub struct UserInfoResponse { pub alleged_user_email: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct GetUserSavedConfigResponse { pub config: UserSavedConfig, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SetDefaultModelParams { /// If set to None, this means `model` should be cleared in config.toml. @@ -456,14 +469,14 @@ pub struct SetDefaultModelParams { pub reasoning_effort: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SetDefaultModelResponse {} /// UserSavedConfig contains a subset of the config. It is meant to expose mcp /// client-configurable settings that can be specified in the NewConversation /// and SendUserTurn requests. -#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, TS)] +#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct UserSavedConfig { /// Approvals @@ -501,7 +514,7 @@ pub struct UserSavedConfig { } /// MCP representation of a [`codex_core::config_profile::ConfigProfile`]. -#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, TS)] +#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct Profile { pub model: Option, @@ -515,7 +528,7 @@ pub struct Profile { pub chatgpt_base_url: Option, } /// MCP representation of a [`codex_core::config::ToolsToml`]. -#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, TS)] +#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct Tools { #[serde(skip_serializing_if = "Option::is_none")] @@ -525,7 +538,7 @@ pub struct Tools { } /// MCP representation of a [`codex_core::config_types::SandboxWorkspaceWrite`]. -#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, TS)] +#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SandboxSettings { #[serde(default)] @@ -538,14 +551,14 @@ pub struct SandboxSettings { pub exclude_slash_tmp: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SendUserMessageParams { pub conversation_id: ConversationId, pub items: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SendUserTurnParams { pub conversation_id: ConversationId, @@ -559,39 +572,40 @@ pub struct SendUserTurnParams { pub summary: ReasoningSummary, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SendUserTurnResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct InterruptConversationParams { pub conversation_id: ConversationId, } -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct InterruptConversationResponse { pub abort_reason: TurnAbortReason, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SendUserMessageResponse {} -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct AddConversationListenerParams { pub conversation_id: ConversationId, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct RemoveConversationListenerParams { + #[schemars(with = "String")] pub subscription_id: Uuid, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[serde(tag = "type", content = "data")] pub enum InputItem { @@ -623,7 +637,7 @@ macro_rules! server_request_definitions { ) => { paste! { /// Request initiated from the server and sent to the client. - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(tag = "method", rename_all = "camelCase")] pub enum ServerRequest { $( @@ -636,7 +650,7 @@ macro_rules! server_request_definitions { )* } - #[derive(Debug, Clone, PartialEq)] + #[derive(Debug, Clone, PartialEq, JsonSchema)] pub enum ServerRequestPayload { $( $variant([<$variant Params>]), )* } @@ -658,6 +672,15 @@ macro_rules! server_request_definitions { } Ok(()) } + + pub fn export_server_response_schemas( + out_dir: &::std::path::Path, + ) -> ::anyhow::Result<()> { + paste! { + $(crate::export::write_json_schema::<[<$variant Response>]>(out_dir, stringify!([<$variant Response>]))?;)* + } + Ok(()) + } }; } @@ -676,7 +699,7 @@ server_request_definitions! { ExecCommandApproval, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ApplyPatchApprovalParams { pub conversation_id: ConversationId, @@ -693,7 +716,7 @@ pub struct ApplyPatchApprovalParams { pub grant_root: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct ExecCommandApprovalParams { pub conversation_id: ConversationId, @@ -707,17 +730,17 @@ pub struct ExecCommandApprovalParams { pub parsed_cmd: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct ExecCommandApprovalResponse { pub decision: ReviewDecision, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct ApplyPatchApprovalResponse { pub decision: ReviewDecision, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(rename_all = "camelCase")] pub struct FuzzyFileSearchParams { @@ -729,7 +752,7 @@ pub struct FuzzyFileSearchParams { } /// Superset of [`codex_file_search::FileMatch`] -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct FuzzyFileSearchResult { pub root: String, pub path: String, @@ -739,21 +762,22 @@ pub struct FuzzyFileSearchResult { pub indices: Option>, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct FuzzyFileSearchResponse { pub files: Vec, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct LoginChatGptCompleteNotification { + #[schemars(with = "String")] pub login_id: Uuid, pub success: bool, #[serde(skip_serializing_if = "Option::is_none")] pub error: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct SessionConfiguredNotification { /// Name left as session_id instead of conversation_id for backwards compatibility. @@ -781,7 +805,7 @@ pub struct SessionConfiguredNotification { pub rollout_path: PathBuf, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] pub struct AuthStatusChangeNotification { /// Current authentication method; omitted if signed out. @@ -790,7 +814,7 @@ pub struct AuthStatusChangeNotification { } /// Notification sent from the server to the client. -#[derive(Serialize, Deserialize, Debug, Clone, TS, Display)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS, Display)] #[serde(tag = "method", content = "params", rename_all = "camelCase")] #[strum(serialize_all = "camelCase")] pub enum ServerNotification { @@ -823,7 +847,7 @@ impl TryFrom for ServerNotification { } /// Notification sent from the client to the server. -#[derive(Serialize, Deserialize, Debug, Clone, TS, Display)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS, Display)] #[serde(tag = "method", content = "params", rename_all = "camelCase")] #[strum(serialize_all = "camelCase")] pub enum ClientNotification { diff --git a/codex-rs/mcp-types/Cargo.toml b/codex-rs/mcp-types/Cargo.toml index c8dc5819cd..8ea4fdfee5 100644 --- a/codex-rs/mcp-types/Cargo.toml +++ b/codex-rs/mcp-types/Cargo.toml @@ -10,3 +10,4 @@ workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } ts-rs = { workspace = true, features = ["serde-json-impl", "no-serde-warnings"] } +schemars = { workspace = true } diff --git a/codex-rs/mcp-types/generate_mcp_types.py b/codex-rs/mcp-types/generate_mcp_types.py index 60c261e828..1906033537 100755 --- a/codex-rs/mcp-types/generate_mcp_types.py +++ b/codex-rs/mcp-types/generate_mcp_types.py @@ -21,9 +21,9 @@ SCHEMA_VERSION = "2025-06-18" JSONRPC_VERSION = "2.0" -STANDARD_DERIVE = "#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)]\n" +STANDARD_DERIVE = "#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)]\n" STANDARD_HASHABLE_DERIVE = ( - "#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, TS)]\n" + "#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, JsonSchema, TS)]\n" ) # Will be populated with the schema's `definitions` map in `main()` so that @@ -94,6 +94,7 @@ def generate_lib_rs(schema_file: Path, lib_rs: Path, fmt: bool) -> None: use serde::de::DeserializeOwned; use std::convert::TryFrom; +use schemars::JsonSchema; use ts_rs::TS; pub const MCP_SCHEMA_VERSION: &str = "{SCHEMA_VERSION}"; diff --git a/codex-rs/mcp-types/src/lib.rs b/codex-rs/mcp-types/src/lib.rs index 37d790ab6a..98dab7252b 100644 --- a/codex-rs/mcp-types/src/lib.rs +++ b/codex-rs/mcp-types/src/lib.rs @@ -10,6 +10,7 @@ use serde::Serialize; use serde::de::DeserializeOwned; use std::convert::TryFrom; +use schemars::JsonSchema; use ts_rs::TS; pub const MCP_SCHEMA_VERSION: &str = "2025-06-18"; @@ -33,7 +34,7 @@ fn default_jsonrpc() -> String { } /// Optional annotations for the client. The client can use annotations to inform how objects are used or displayed -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Annotations { #[serde(default, skip_serializing_if = "Option::is_none")] pub audience: Option>, @@ -48,7 +49,7 @@ pub struct Annotations { } /// Audio provided to or from an LLM. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct AudioContent { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -59,14 +60,14 @@ pub struct AudioContent { } /// Base interface for metadata with name (identifier) and title (display name) properties. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct BaseMetadata { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub title: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct BlobResourceContents { pub blob: String, #[serde(rename = "mimeType", default, skip_serializing_if = "Option::is_none")] @@ -74,7 +75,7 @@ pub struct BlobResourceContents { pub uri: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct BooleanSchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub default: Option, @@ -85,7 +86,7 @@ pub struct BooleanSchema { pub r#type: String, // &'static str = "boolean" } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum CallToolRequest {} impl ModelContextProtocolRequest for CallToolRequest { @@ -94,7 +95,7 @@ impl ModelContextProtocolRequest for CallToolRequest { type Result = CallToolResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CallToolRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub arguments: Option, @@ -102,7 +103,7 @@ pub struct CallToolRequestParams { } /// The server's response to a tool call. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CallToolResult { pub content: Vec, #[serde(rename = "isError", default, skip_serializing_if = "Option::is_none")] @@ -123,7 +124,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum CancelledNotification {} impl ModelContextProtocolNotification for CancelledNotification { @@ -131,7 +132,7 @@ impl ModelContextProtocolNotification for CancelledNotification { type Params = CancelledNotificationParams; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CancelledNotificationParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub reason: Option, @@ -140,7 +141,7 @@ pub struct CancelledNotificationParams { } /// Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ClientCapabilities { #[serde(default, skip_serializing_if = "Option::is_none")] pub elicitation: Option, @@ -153,7 +154,7 @@ pub struct ClientCapabilities { } /// Present if the client supports listing roots. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ClientCapabilitiesRoots { #[serde( rename = "listChanged", @@ -163,7 +164,7 @@ pub struct ClientCapabilitiesRoots { pub list_changed: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum ClientNotification { CancelledNotification(CancelledNotification), @@ -172,7 +173,7 @@ pub enum ClientNotification { RootsListChangedNotification(RootsListChangedNotification), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(tag = "method", content = "params")] pub enum ClientRequest { #[serde(rename = "initialize")] @@ -205,7 +206,7 @@ pub enum ClientRequest { CompleteRequest(::Params), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum ClientResult { Result(Result), @@ -214,7 +215,7 @@ pub enum ClientResult { ElicitResult(ElicitResult), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum CompleteRequest {} impl ModelContextProtocolRequest for CompleteRequest { @@ -223,7 +224,7 @@ impl ModelContextProtocolRequest for CompleteRequest { type Result = CompleteResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CompleteRequestParams { pub argument: CompleteRequestParamsArgument, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -232,20 +233,20 @@ pub struct CompleteRequestParams { } /// Additional, optional context for completions -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CompleteRequestParamsContext { #[serde(default, skip_serializing_if = "Option::is_none")] pub arguments: Option, } /// The argument's information -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CompleteRequestParamsArgument { pub name: String, pub value: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum CompleteRequestParamsRef { PromptReference(PromptReference), @@ -253,12 +254,12 @@ pub enum CompleteRequestParamsRef { } /// The server's response to a completion/complete request -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CompleteResult { pub completion: CompleteResultCompletion, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CompleteResultCompletion { #[serde(rename = "hasMore", default, skip_serializing_if = "Option::is_none")] pub has_more: Option, @@ -275,7 +276,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum ContentBlock { TextContent(TextContent), @@ -285,7 +286,7 @@ pub enum ContentBlock { EmbeddedResource(EmbeddedResource), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum CreateMessageRequest {} impl ModelContextProtocolRequest for CreateMessageRequest { @@ -294,7 +295,7 @@ impl ModelContextProtocolRequest for CreateMessageRequest { type Result = CreateMessageResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CreateMessageRequestParams { #[serde( rename = "includeContext", @@ -330,7 +331,7 @@ pub struct CreateMessageRequestParams { } /// The client's response to a sampling/create_message request from the server. The client should inform the user before returning the sampled message, to allow them to inspect the response (human in the loop) and decide whether to allow the server to see it. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct CreateMessageResult { pub content: CreateMessageResultContent, pub model: String, @@ -343,7 +344,7 @@ pub struct CreateMessageResult { pub stop_reason: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum CreateMessageResultContent { TextContent(TextContent), @@ -359,10 +360,10 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Cursor(String); -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ElicitRequest {} impl ModelContextProtocolRequest for ElicitRequest { @@ -371,7 +372,7 @@ impl ModelContextProtocolRequest for ElicitRequest { type Result = ElicitResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ElicitRequestParams { pub message: String, #[serde(rename = "requestedSchema")] @@ -380,7 +381,7 @@ pub struct ElicitRequestParams { /// A restricted subset of JSON Schema. /// Only top-level properties are allowed, without nesting. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ElicitRequestParamsRequestedSchema { pub properties: serde_json::Value, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -389,7 +390,7 @@ pub struct ElicitRequestParamsRequestedSchema { } /// The client's response to an elicitation request. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ElicitResult { pub action: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -408,7 +409,7 @@ impl From for serde_json::Value { /// /// It is up to the client how best to render embedded resources for the benefit /// of the LLM and/or the user. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct EmbeddedResource { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -416,7 +417,7 @@ pub struct EmbeddedResource { pub r#type: String, // &'static str = "resource" } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum EmbeddedResourceResource { TextResourceContents(TextResourceContents), @@ -425,7 +426,7 @@ pub enum EmbeddedResourceResource { pub type EmptyResult = Result; -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct EnumSchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, @@ -437,7 +438,7 @@ pub struct EnumSchema { pub r#type: String, // &'static str = "string" } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum GetPromptRequest {} impl ModelContextProtocolRequest for GetPromptRequest { @@ -446,7 +447,7 @@ impl ModelContextProtocolRequest for GetPromptRequest { type Result = GetPromptResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct GetPromptRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub arguments: Option, @@ -454,7 +455,7 @@ pub struct GetPromptRequestParams { } /// The server's response to a prompts/get request from the client. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct GetPromptResult { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, @@ -470,7 +471,7 @@ impl From for serde_json::Value { } /// An image provided to or from an LLM. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ImageContent { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -481,7 +482,7 @@ pub struct ImageContent { } /// Describes the name and version of an MCP implementation, with an optional title for UI representation. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Implementation { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -492,7 +493,7 @@ pub struct Implementation { pub user_agent: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum InitializeRequest {} impl ModelContextProtocolRequest for InitializeRequest { @@ -501,7 +502,7 @@ impl ModelContextProtocolRequest for InitializeRequest { type Result = InitializeResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct InitializeRequestParams { pub capabilities: ClientCapabilities, #[serde(rename = "clientInfo")] @@ -511,7 +512,7 @@ pub struct InitializeRequestParams { } /// After receiving an initialize request from the client, the server sends this response. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct InitializeResult { pub capabilities: ServerCapabilities, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -530,7 +531,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum InitializedNotification {} impl ModelContextProtocolNotification for InitializedNotification { @@ -539,7 +540,7 @@ impl ModelContextProtocolNotification for InitializedNotification { } /// A response to a request that indicates an error occurred. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCError { pub error: JSONRPCErrorError, pub id: RequestId, @@ -547,7 +548,7 @@ pub struct JSONRPCError { pub jsonrpc: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCErrorError { pub code: i64, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -556,7 +557,7 @@ pub struct JSONRPCErrorError { } /// Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum JSONRPCMessage { Request(JSONRPCRequest), @@ -566,7 +567,7 @@ pub enum JSONRPCMessage { } /// A notification which does not expect a response. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCNotification { #[serde(rename = "jsonrpc", default = "default_jsonrpc")] pub jsonrpc: String, @@ -576,7 +577,7 @@ pub struct JSONRPCNotification { } /// A request that expects a response. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCRequest { pub id: RequestId, #[serde(rename = "jsonrpc", default = "default_jsonrpc")] @@ -587,7 +588,7 @@ pub struct JSONRPCRequest { } /// A successful (non-error) response to a request. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct JSONRPCResponse { pub id: RequestId, #[serde(rename = "jsonrpc", default = "default_jsonrpc")] @@ -595,7 +596,7 @@ pub struct JSONRPCResponse { pub result: Result, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ListPromptsRequest {} impl ModelContextProtocolRequest for ListPromptsRequest { @@ -604,14 +605,14 @@ impl ModelContextProtocolRequest for ListPromptsRequest { type Result = ListPromptsResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListPromptsRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub cursor: Option, } /// The server's response to a prompts/list request from the client. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListPromptsResult { #[serde( rename = "nextCursor", @@ -630,7 +631,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ListResourceTemplatesRequest {} impl ModelContextProtocolRequest for ListResourceTemplatesRequest { @@ -639,14 +640,14 @@ impl ModelContextProtocolRequest for ListResourceTemplatesRequest { type Result = ListResourceTemplatesResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListResourceTemplatesRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub cursor: Option, } /// The server's response to a resources/templates/list request from the client. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListResourceTemplatesResult { #[serde( rename = "nextCursor", @@ -666,7 +667,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ListResourcesRequest {} impl ModelContextProtocolRequest for ListResourcesRequest { @@ -675,14 +676,14 @@ impl ModelContextProtocolRequest for ListResourcesRequest { type Result = ListResourcesResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListResourcesRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub cursor: Option, } /// The server's response to a resources/list request from the client. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListResourcesResult { #[serde( rename = "nextCursor", @@ -701,7 +702,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ListRootsRequest {} impl ModelContextProtocolRequest for ListRootsRequest { @@ -713,7 +714,7 @@ impl ModelContextProtocolRequest for ListRootsRequest { /// The client's response to a roots/list request from the server. /// This result contains an array of Root objects, each representing a root directory /// or file that the server can operate on. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListRootsResult { pub roots: Vec, } @@ -726,7 +727,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ListToolsRequest {} impl ModelContextProtocolRequest for ListToolsRequest { @@ -735,14 +736,14 @@ impl ModelContextProtocolRequest for ListToolsRequest { type Result = ListToolsResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListToolsRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub cursor: Option, } /// The server's response to a tools/list request from the client. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ListToolsResult { #[serde( rename = "nextCursor", @@ -765,7 +766,7 @@ impl From for serde_json::Value { /// /// These map to syslog message severities, as specified in RFC-5424: /// https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1 -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum LoggingLevel { #[serde(rename = "alert")] Alert, @@ -785,7 +786,7 @@ pub enum LoggingLevel { Warning, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum LoggingMessageNotification {} impl ModelContextProtocolNotification for LoggingMessageNotification { @@ -793,7 +794,7 @@ impl ModelContextProtocolNotification for LoggingMessageNotification { type Params = LoggingMessageNotificationParams; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct LoggingMessageNotificationParams { pub data: serde_json::Value, pub level: LoggingLevel, @@ -805,7 +806,7 @@ pub struct LoggingMessageNotificationParams { /// /// Keys not declared here are currently left unspecified by the spec and are up /// to the client to interpret. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ModelHint { #[serde(default, skip_serializing_if = "Option::is_none")] pub name: Option, @@ -822,7 +823,7 @@ pub struct ModelHint { /// These preferences are always advisory. The client MAY ignore them. It is also /// up to the client to decide how to interpret these preferences and how to /// balance them against other considerations. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ModelPreferences { #[serde( rename = "costPriority", @@ -846,14 +847,14 @@ pub struct ModelPreferences { pub speed_priority: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Notification { pub method: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub params: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct NumberSchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, @@ -866,20 +867,20 @@ pub struct NumberSchema { pub r#type: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct PaginatedRequest { pub method: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub params: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct PaginatedRequestParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub cursor: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct PaginatedResult { #[serde( rename = "nextCursor", @@ -897,7 +898,7 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum PingRequest {} impl ModelContextProtocolRequest for PingRequest { @@ -908,7 +909,7 @@ impl ModelContextProtocolRequest for PingRequest { /// Restricted schema definitions that only allow primitive types /// without nested objects or arrays. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum PrimitiveSchemaDefinition { StringSchema(StringSchema), @@ -917,7 +918,7 @@ pub enum PrimitiveSchemaDefinition { EnumSchema(EnumSchema), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ProgressNotification {} impl ModelContextProtocolNotification for ProgressNotification { @@ -925,7 +926,7 @@ impl ModelContextProtocolNotification for ProgressNotification { type Params = ProgressNotificationParams; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ProgressNotificationParams { #[serde(default, skip_serializing_if = "Option::is_none")] pub message: Option, @@ -936,7 +937,7 @@ pub struct ProgressNotificationParams { pub total: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, JsonSchema, TS)] #[serde(untagged)] pub enum ProgressToken { String(String), @@ -944,7 +945,7 @@ pub enum ProgressToken { } /// A prompt or prompt template that the server offers. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Prompt { #[serde(default, skip_serializing_if = "Option::is_none")] pub arguments: Option>, @@ -956,7 +957,7 @@ pub struct Prompt { } /// Describes an argument that a prompt can accept. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct PromptArgument { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, @@ -967,7 +968,7 @@ pub struct PromptArgument { pub title: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum PromptListChangedNotification {} impl ModelContextProtocolNotification for PromptListChangedNotification { @@ -979,14 +980,14 @@ impl ModelContextProtocolNotification for PromptListChangedNotification { /// /// This is similar to `SamplingMessage`, but also supports the embedding of /// resources from the MCP server. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct PromptMessage { pub content: ContentBlock, pub role: Role, } /// Identifies a prompt. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct PromptReference { pub name: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -994,7 +995,7 @@ pub struct PromptReference { pub r#type: String, // &'static str = "ref/prompt" } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ReadResourceRequest {} impl ModelContextProtocolRequest for ReadResourceRequest { @@ -1003,18 +1004,18 @@ impl ModelContextProtocolRequest for ReadResourceRequest { type Result = ReadResourceResult; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ReadResourceRequestParams { pub uri: String, } /// The server's response to a resources/read request from the client. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ReadResourceResult { pub contents: Vec, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum ReadResourceResultContents { TextResourceContents(TextResourceContents), @@ -1029,14 +1030,14 @@ impl From for serde_json::Value { } } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Request { pub method: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub params: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Hash, Eq, JsonSchema, TS)] #[serde(untagged)] pub enum RequestId { String(String), @@ -1044,7 +1045,7 @@ pub enum RequestId { } /// A known resource that the server is capable of reading. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Resource { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -1061,7 +1062,7 @@ pub struct Resource { } /// The contents of a specific resource or sub-resource. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ResourceContents { #[serde(rename = "mimeType", default, skip_serializing_if = "Option::is_none")] pub mime_type: Option, @@ -1071,7 +1072,7 @@ pub struct ResourceContents { /// A resource that the server is capable of reading, included in a prompt or tool call result. /// /// Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ResourceLink { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -1088,7 +1089,7 @@ pub struct ResourceLink { pub uri: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ResourceListChangedNotification {} impl ModelContextProtocolNotification for ResourceListChangedNotification { @@ -1097,7 +1098,7 @@ impl ModelContextProtocolNotification for ResourceListChangedNotification { } /// A template description for resources available on the server. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ResourceTemplate { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -1113,13 +1114,13 @@ pub struct ResourceTemplate { } /// A reference to a resource or resource template definition. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ResourceTemplateReference { pub r#type: String, // &'static str = "ref/resource" pub uri: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ResourceUpdatedNotification {} impl ModelContextProtocolNotification for ResourceUpdatedNotification { @@ -1127,7 +1128,7 @@ impl ModelContextProtocolNotification for ResourceUpdatedNotification { type Params = ResourceUpdatedNotificationParams; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ResourceUpdatedNotificationParams { pub uri: String, } @@ -1135,7 +1136,7 @@ pub struct ResourceUpdatedNotificationParams { pub type Result = serde_json::Value; /// The sender or recipient of messages and data in a conversation. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum Role { #[serde(rename = "assistant")] Assistant, @@ -1144,14 +1145,14 @@ pub enum Role { } /// Represents a root directory or file that the server can operate on. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Root { #[serde(default, skip_serializing_if = "Option::is_none")] pub name: Option, pub uri: String, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum RootsListChangedNotification {} impl ModelContextProtocolNotification for RootsListChangedNotification { @@ -1160,13 +1161,13 @@ impl ModelContextProtocolNotification for RootsListChangedNotification { } /// Describes a message issued to or received from an LLM API. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct SamplingMessage { pub content: SamplingMessageContent, pub role: Role, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum SamplingMessageContent { TextContent(TextContent), @@ -1175,7 +1176,7 @@ pub enum SamplingMessageContent { } /// Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ServerCapabilities { #[serde(default, skip_serializing_if = "Option::is_none")] pub completions: Option, @@ -1192,7 +1193,7 @@ pub struct ServerCapabilities { } /// Present if the server offers any tools to call. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ServerCapabilitiesTools { #[serde( rename = "listChanged", @@ -1203,7 +1204,7 @@ pub struct ServerCapabilitiesTools { } /// Present if the server offers any resources to read. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ServerCapabilitiesResources { #[serde( rename = "listChanged", @@ -1216,7 +1217,7 @@ pub struct ServerCapabilitiesResources { } /// Present if the server offers any prompt templates. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ServerCapabilitiesPrompts { #[serde( rename = "listChanged", @@ -1226,7 +1227,7 @@ pub struct ServerCapabilitiesPrompts { pub list_changed: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(tag = "method", content = "params")] pub enum ServerNotification { #[serde(rename = "notifications/cancelled")] @@ -1255,7 +1256,7 @@ pub enum ServerNotification { ), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] pub enum ServerRequest { PingRequest(PingRequest), @@ -1264,7 +1265,7 @@ pub enum ServerRequest { ElicitRequest(ElicitRequest), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] #[serde(untagged)] #[allow(clippy::large_enum_variant)] pub enum ServerResult { @@ -1280,7 +1281,7 @@ pub enum ServerResult { CompleteResult(CompleteResult), } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum SetLevelRequest {} impl ModelContextProtocolRequest for SetLevelRequest { @@ -1289,12 +1290,12 @@ impl ModelContextProtocolRequest for SetLevelRequest { type Result = Result; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct SetLevelRequestParams { pub level: LoggingLevel, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct StringSchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub description: Option, @@ -1309,7 +1310,7 @@ pub struct StringSchema { pub r#type: String, // &'static str = "string" } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum SubscribeRequest {} impl ModelContextProtocolRequest for SubscribeRequest { @@ -1318,13 +1319,13 @@ impl ModelContextProtocolRequest for SubscribeRequest { type Result = Result; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct SubscribeRequestParams { pub uri: String, } /// Text provided to or from an LLM. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct TextContent { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -1332,7 +1333,7 @@ pub struct TextContent { pub r#type: String, // &'static str = "text" } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct TextResourceContents { #[serde(rename = "mimeType", default, skip_serializing_if = "Option::is_none")] pub mime_type: Option, @@ -1341,7 +1342,7 @@ pub struct TextResourceContents { } /// Definition for a tool the client can call. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct Tool { #[serde(default, skip_serializing_if = "Option::is_none")] pub annotations: Option, @@ -1362,7 +1363,7 @@ pub struct Tool { /// An optional JSON Schema object defining the structure of the tool's output returned in /// the structuredContent field of a CallToolResult. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ToolOutputSchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub properties: Option, @@ -1372,7 +1373,7 @@ pub struct ToolOutputSchema { } /// A JSON Schema object defining the expected parameters for the tool. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ToolInputSchema { #[serde(default, skip_serializing_if = "Option::is_none")] pub properties: Option, @@ -1389,7 +1390,7 @@ pub struct ToolInputSchema { /// /// Clients should never make tool use decisions based on ToolAnnotations /// received from untrusted servers. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct ToolAnnotations { #[serde( rename = "destructiveHint", @@ -1419,7 +1420,7 @@ pub struct ToolAnnotations { pub title: Option, } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum ToolListChangedNotification {} impl ModelContextProtocolNotification for ToolListChangedNotification { @@ -1427,7 +1428,7 @@ impl ModelContextProtocolNotification for ToolListChangedNotification { type Params = Option; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub enum UnsubscribeRequest {} impl ModelContextProtocolRequest for UnsubscribeRequest { @@ -1436,7 +1437,7 @@ impl ModelContextProtocolRequest for UnsubscribeRequest { type Result = Result; } -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, TS)] pub struct UnsubscribeRequestParams { pub uri: String, } diff --git a/codex-rs/protocol/Cargo.toml b/codex-rs/protocol/Cargo.toml index 72cf984e96..f21d326610 100644 --- a/codex-rs/protocol/Cargo.toml +++ b/codex-rs/protocol/Cargo.toml @@ -19,6 +19,7 @@ mime_guess = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_with = { workspace = true, features = ["macros", "base64"] } +schemars = { workspace = true } strum = { workspace = true } strum_macros = { workspace = true } sys-locale = { workspace = true } diff --git a/codex-rs/protocol/src/config_types.rs b/codex-rs/protocol/src/config_types.rs index d701ecf41e..32950527bc 100644 --- a/codex-rs/protocol/src/config_types.rs +++ b/codex-rs/protocol/src/config_types.rs @@ -1,3 +1,4 @@ +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use strum_macros::Display; @@ -6,7 +7,18 @@ use ts_rs::TS; /// See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning #[derive( - Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Display, TS, EnumIter, + Debug, + Serialize, + Deserialize, + Default, + Clone, + Copy, + PartialEq, + Eq, + Display, + JsonSchema, + TS, + EnumIter, )] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] @@ -21,7 +33,9 @@ pub enum ReasoningEffort { /// A summary of the reasoning performed by the model. This can be useful for /// debugging and understanding the model's reasoning process. /// See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#reasoning-summaries -#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Display, TS)] +#[derive( + Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Display, JsonSchema, TS, +)] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] pub enum ReasoningSummary { @@ -35,7 +49,9 @@ pub enum ReasoningSummary { /// Controls output length/detail on GPT-5 models via the Responses API. /// Serialized with lowercase values to match the OpenAI API. -#[derive(Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Display, TS)] +#[derive( + Debug, Serialize, Deserialize, Default, Clone, Copy, PartialEq, Eq, Display, JsonSchema, TS, +)] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] pub enum Verbosity { @@ -45,7 +61,9 @@ pub enum Verbosity { High, } -#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Default, Serialize, Display, TS)] +#[derive( + Deserialize, Debug, Clone, Copy, PartialEq, Default, Serialize, Display, JsonSchema, TS, +)] #[serde(rename_all = "kebab-case")] #[strum(serialize_all = "kebab-case")] pub enum SandboxMode { @@ -60,7 +78,7 @@ pub enum SandboxMode { DangerFullAccess, } -#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Display, TS)] +#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Display, JsonSchema, TS)] #[serde(rename_all = "lowercase")] #[strum(serialize_all = "lowercase")] pub enum ForcedLoginMethod { diff --git a/codex-rs/protocol/src/conversation_id.rs b/codex-rs/protocol/src/conversation_id.rs index 687237e0ab..db104d4531 100644 --- a/codex-rs/protocol/src/conversation_id.rs +++ b/codex-rs/protocol/src/conversation_id.rs @@ -1,5 +1,8 @@ use std::fmt::Display; +use schemars::JsonSchema; +use schemars::r#gen::SchemaGenerator; +use schemars::schema::Schema; use serde::Deserialize; use serde::Serialize; use ts_rs::TS; @@ -57,6 +60,16 @@ impl<'de> Deserialize<'de> for ConversationId { } } +impl JsonSchema for ConversationId { + fn schema_name() -> String { + "ConversationId".to_string() + } + + fn json_schema(generator: &mut SchemaGenerator) -> Schema { + ::json_schema(generator) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/codex-rs/protocol/src/custom_prompts.rs b/codex-rs/protocol/src/custom_prompts.rs index 4839cba3c2..7472d1b4c5 100644 --- a/codex-rs/protocol/src/custom_prompts.rs +++ b/codex-rs/protocol/src/custom_prompts.rs @@ -1,3 +1,4 @@ +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::path::PathBuf; @@ -9,7 +10,7 @@ use ts_rs::TS; /// - Full slash prefix: `"/{PROMPTS_CMD_PREFIX}:"` pub const PROMPTS_CMD_PREFIX: &str = "prompts"; -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] pub struct CustomPrompt { pub name: String, pub path: PathBuf, diff --git a/codex-rs/protocol/src/message_history.rs b/codex-rs/protocol/src/message_history.rs index ba79993131..0d8bd8df4e 100644 --- a/codex-rs/protocol/src/message_history.rs +++ b/codex-rs/protocol/src/message_history.rs @@ -1,8 +1,9 @@ +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use ts_rs::TS; -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] pub struct HistoryEntry { pub conversation_id: String, pub ts: u64, diff --git a/codex-rs/protocol/src/models.rs b/codex-rs/protocol/src/models.rs index 4952aa01d9..285ae666f9 100644 --- a/codex-rs/protocol/src/models.rs +++ b/codex-rs/protocol/src/models.rs @@ -9,8 +9,9 @@ use serde::ser::Serializer; use ts_rs::TS; use crate::protocol::InputItem; +use schemars::JsonSchema; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ResponseInputItem { Message { @@ -31,7 +32,7 @@ pub enum ResponseInputItem { }, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ContentItem { InputText { text: String }, @@ -39,7 +40,7 @@ pub enum ContentItem { OutputText { text: String }, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ResponseItem { Message { @@ -159,7 +160,7 @@ impl From for ResponseItem { } } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum LocalShellStatus { Completed, @@ -167,13 +168,13 @@ pub enum LocalShellStatus { Incomplete, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum LocalShellAction { Exec(LocalShellExecAction), } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] pub struct LocalShellExecAction { pub command: Vec, pub timeout_ms: Option, @@ -182,7 +183,7 @@ pub struct LocalShellExecAction { pub user: Option, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum WebSearchAction { Search { @@ -192,13 +193,13 @@ pub enum WebSearchAction { Other, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ReasoningItemReasoningSummary { SummaryText { text: String }, } -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ReasoningItemContent { ReasoningText { text: String }, @@ -242,7 +243,7 @@ impl From> for ResponseInputItem { /// If the `name` of a `ResponseItem::FunctionCall` is either `container.exec` /// or shell`, the `arguments` field should deserialize to this struct. -#[derive(Deserialize, Debug, Clone, PartialEq, TS)] +#[derive(Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] pub struct ShellToolCallParams { pub command: Vec, pub workdir: Option, @@ -256,7 +257,7 @@ pub struct ShellToolCallParams { pub justification: Option, } -#[derive(Debug, Clone, PartialEq, TS)] +#[derive(Debug, Clone, PartialEq, JsonSchema, TS)] pub struct FunctionCallOutputPayload { pub content: String, // TODO(jif) drop this. diff --git a/codex-rs/protocol/src/parse_command.rs b/codex-rs/protocol/src/parse_command.rs index b06e290436..77926f11b6 100644 --- a/codex-rs/protocol/src/parse_command.rs +++ b/codex-rs/protocol/src/parse_command.rs @@ -1,9 +1,10 @@ +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use std::path::PathBuf; use ts_rs::TS; -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] pub enum ParsedCommand { Read { diff --git a/codex-rs/protocol/src/plan_tool.rs b/codex-rs/protocol/src/plan_tool.rs index 79e672ac73..a9038eb03b 100644 --- a/codex-rs/protocol/src/plan_tool.rs +++ b/codex-rs/protocol/src/plan_tool.rs @@ -1,9 +1,10 @@ +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use ts_rs::TS; // Types for the TODO tool arguments matching codex-vscode/todo-mcp/src/main.rs -#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum StepStatus { Pending, @@ -11,14 +12,14 @@ pub enum StepStatus { Completed, } -#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, TS)] #[serde(deny_unknown_fields)] pub struct PlanItemArg { pub step: String, pub status: StepStatus, } -#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, TS)] #[serde(deny_unknown_fields)] pub struct UpdatePlanArgs { #[serde(default)] diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 5429e4d402..94b9da019e 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -24,6 +24,7 @@ use mcp_types::CallToolResult; use mcp_types::Resource as McpResource; use mcp_types::ResourceTemplate as McpResourceTemplate; use mcp_types::Tool as McpTool; +use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use serde_json::Value; @@ -40,7 +41,7 @@ pub const ENVIRONMENT_CONTEXT_CLOSE_TAG: &str = ""; pub const USER_MESSAGE_BEGIN: &str = "## My request for Codex:"; /// Submission Queue Entry - requests from user -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] pub struct Submission { /// Unique id for this Submission to correlate with Events pub id: String, @@ -49,7 +50,7 @@ pub struct Submission { } /// Submission operation -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema)] #[serde(tag = "type", rename_all = "snake_case")] #[allow(clippy::large_enum_variant)] #[non_exhaustive] @@ -182,7 +183,20 @@ pub enum Op { /// Determines the conditions under which the user is consulted to approve /// running the command proposed by Codex. -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Serialize, Deserialize, Display, TS)] +#[derive( + Debug, + Clone, + Copy, + Default, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + Display, + JsonSchema, + TS, +)] #[serde(rename_all = "kebab-case")] #[strum(serialize_all = "kebab-case")] pub enum AskForApproval { @@ -209,7 +223,7 @@ pub enum AskForApproval { } /// Determines execution restrictions for model shell commands. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Display, TS)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Display, JsonSchema, TS)] #[strum(serialize_all = "kebab-case")] #[serde(tag = "mode", rename_all = "kebab-case")] pub enum SandboxPolicy { @@ -252,7 +266,7 @@ pub enum SandboxPolicy { /// read‑only even when the root is writable. This is primarily used to ensure /// top‑level VCS metadata directories (e.g. `.git`) under a writable root are /// not modified by the agent. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, JsonSchema)] pub struct WritableRoot { /// Absolute path, by construction. pub root: PathBuf, @@ -391,7 +405,7 @@ impl SandboxPolicy { /// User input #[non_exhaustive] -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema)] #[serde(tag = "type", rename_all = "snake_case")] pub enum InputItem { Text { @@ -410,7 +424,7 @@ pub enum InputItem { } /// Event Queue Entry - events from agent -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] pub struct Event { /// Submission `id` that this event is correlated with. pub id: String, @@ -420,7 +434,7 @@ pub struct Event { /// Response event from the agent /// NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen. -#[derive(Debug, Clone, Deserialize, Serialize, Display, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, Display, JsonSchema, TS)] #[serde(tag = "type", rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum EventMsg { @@ -526,29 +540,29 @@ pub enum EventMsg { ExitedReviewMode(ExitedReviewModeEvent), } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ExitedReviewModeEvent { pub review_output: Option, } // Individual event payload types matching each `EventMsg` variant. -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ErrorEvent { pub message: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct TaskCompleteEvent { pub last_agent_message: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct TaskStartedEvent { pub model_context_window: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, Default, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, Default, JsonSchema, TS)] pub struct TokenUsage { #[ts(type = "number")] pub input_tokens: u64, @@ -562,7 +576,7 @@ pub struct TokenUsage { pub total_tokens: u64, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct TokenUsageInfo { pub total_token_usage: TokenUsage, pub last_token_usage: TokenUsage, @@ -625,19 +639,19 @@ impl TokenUsageInfo { } } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct TokenCountEvent { pub info: Option, pub rate_limits: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct RateLimitSnapshot { pub primary: Option, pub secondary: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct RateLimitWindow { /// Percentage (0-100) of the window that has been consumed. pub used_percent: f64, @@ -712,7 +726,7 @@ impl TokenUsage { } } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] pub struct FinalOutput { pub token_usage: TokenUsage, } @@ -753,12 +767,12 @@ impl fmt::Display for FinalOutput { } } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentMessageEvent { pub message: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum InputMessageKind { /// Plain user text (default) @@ -769,7 +783,7 @@ pub enum InputMessageKind { EnvironmentContext, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct UserMessageEvent { pub message: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -821,35 +835,35 @@ fn ends_with_ignore_ascii_case(text: &str, suffix: &str) -> bool { .all(|(a, b)| a.eq_ignore_ascii_case(b)) } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentMessageDeltaEvent { pub delta: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningEvent { pub text: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningRawContentEvent { pub text: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningRawContentDeltaEvent { pub delta: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningSectionBreakEvent {} -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct AgentReasoningDeltaEvent { pub delta: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct McpInvocation { /// Name of the MCP server as defined in the config. pub server: String, @@ -859,14 +873,14 @@ pub struct McpInvocation { pub arguments: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct McpToolCallBeginEvent { /// Identifier so this can be paired with the McpToolCallEnd event. pub call_id: String, pub invocation: McpInvocation, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct McpToolCallEndEvent { /// Identifier for the corresponding McpToolCallBegin that finished. pub call_id: String, @@ -886,12 +900,12 @@ impl McpToolCallEndEvent { } } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct WebSearchBeginEvent { pub call_id: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct WebSearchEndEvent { pub call_id: String, pub query: String, @@ -899,20 +913,20 @@ pub struct WebSearchEndEvent { /// Response payload for `Op::GetHistory` containing the current session's /// in-memory transcript. -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ConversationPathResponseEvent { pub conversation_id: ConversationId, pub path: PathBuf, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ResumedHistory { pub conversation_id: ConversationId, pub history: Vec, pub rollout_path: PathBuf, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub enum InitialHistory { New, Resumed(ResumedHistory), @@ -954,7 +968,7 @@ impl InitialHistory { } } -#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, TS, Default)] +#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, JsonSchema, TS, Default)] #[serde(rename_all = "lowercase")] #[ts(rename_all = "lowercase")] pub enum SessionSource { @@ -967,7 +981,7 @@ pub enum SessionSource { Unknown, } -#[derive(Serialize, Deserialize, Clone, Debug, TS)] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, TS)] pub struct SessionMeta { pub id: ConversationId, pub timestamp: String, @@ -993,7 +1007,7 @@ impl Default for SessionMeta { } } -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] pub struct SessionMetaLine { #[serde(flatten)] pub meta: SessionMeta, @@ -1001,7 +1015,7 @@ pub struct SessionMetaLine { pub git: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, TS)] #[serde(tag = "type", content = "payload", rename_all = "snake_case")] pub enum RolloutItem { SessionMeta(SessionMetaLine), @@ -1011,7 +1025,7 @@ pub enum RolloutItem { EventMsg(EventMsg), } -#[derive(Serialize, Deserialize, Clone, Debug, TS)] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, TS)] pub struct CompactedItem { pub message: String, } @@ -1028,7 +1042,7 @@ impl From for ResponseItem { } } -#[derive(Serialize, Deserialize, Clone, Debug, TS)] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, TS)] pub struct TurnContextItem { pub cwd: PathBuf, pub approval_policy: AskForApproval, @@ -1039,14 +1053,14 @@ pub struct TurnContextItem { pub summary: ReasoningSummaryConfig, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, JsonSchema)] pub struct RolloutLine { pub timestamp: String, #[serde(flatten)] pub item: RolloutItem, } -#[derive(Serialize, Deserialize, Clone, Debug, TS)] +#[derive(Serialize, Deserialize, Clone, Debug, JsonSchema, TS)] pub struct GitInfo { /// Current commit hash (SHA) #[serde(skip_serializing_if = "Option::is_none")] @@ -1060,14 +1074,14 @@ pub struct GitInfo { } /// Review request sent to the review session. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ReviewRequest { pub prompt: String, pub user_facing_hint: String, } /// Structured review result produced by a child review session. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ReviewOutputEvent { pub findings: Vec, pub overall_correctness: String, @@ -1087,7 +1101,7 @@ impl Default for ReviewOutputEvent { } /// A single review finding describing an observed issue or recommendation. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ReviewFinding { pub title: String, pub body: String, @@ -1097,20 +1111,20 @@ pub struct ReviewFinding { } /// Location of the code related to a review finding. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ReviewCodeLocation { pub absolute_file_path: PathBuf, pub line_range: ReviewLineRange, } /// Inclusive line range in a file associated with the finding. -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ReviewLineRange { pub start: u32, pub end: u32, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ExecCommandBeginEvent { /// Identifier so this can be paired with the ExecCommandEnd event. pub call_id: String, @@ -1121,7 +1135,7 @@ pub struct ExecCommandBeginEvent { pub parsed_cmd: Vec, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ExecCommandEndEvent { /// Identifier for the ExecCommandBegin that finished. pub call_id: String, @@ -1141,7 +1155,7 @@ pub struct ExecCommandEndEvent { pub formatted_output: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ViewImageToolCallEvent { /// Identifier for the originating tool call. pub call_id: String, @@ -1149,7 +1163,7 @@ pub struct ViewImageToolCallEvent { pub path: PathBuf, } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum ExecOutputStream { Stdout, @@ -1157,7 +1171,7 @@ pub enum ExecOutputStream { } #[serde_as] -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct ExecCommandOutputDeltaEvent { /// Identifier for the ExecCommandBegin that produced this chunk. pub call_id: String, @@ -1165,11 +1179,12 @@ pub struct ExecCommandOutputDeltaEvent { pub stream: ExecOutputStream, /// Raw bytes from the stream (may not be valid UTF-8). #[serde_as(as = "serde_with::base64::Base64")] + #[schemars(with = "String")] #[ts(type = "string")] pub chunk: Vec, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ExecApprovalRequestEvent { /// Identifier for the associated exec call, if available. pub call_id: String, @@ -1183,7 +1198,7 @@ pub struct ExecApprovalRequestEvent { pub parsed_cmd: Vec, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ApplyPatchApprovalRequestEvent { /// Responses API call id for the associated patch apply call, if available. pub call_id: String, @@ -1196,22 +1211,22 @@ pub struct ApplyPatchApprovalRequestEvent { pub grant_root: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct BackgroundEventEvent { pub message: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct StreamErrorEvent { pub message: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct StreamInfoEvent { pub message: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct PatchApplyBeginEvent { /// Identifier so this can be paired with the PatchApplyEnd event. pub call_id: String, @@ -1221,7 +1236,7 @@ pub struct PatchApplyBeginEvent { pub changes: HashMap, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct PatchApplyEndEvent { /// Identifier for the PatchApplyBegin that finished. pub call_id: String, @@ -1233,12 +1248,12 @@ pub struct PatchApplyEndEvent { pub success: bool, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct TurnDiffEvent { pub unified_diff: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct GetHistoryEntryResponseEvent { pub offset: usize, pub log_id: u64, @@ -1247,7 +1262,7 @@ pub struct GetHistoryEntryResponseEvent { pub entry: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct McpListToolsResponseEvent { /// Fully qualified tool name -> tool definition. pub tools: std::collections::HashMap, @@ -1259,7 +1274,7 @@ pub struct McpListToolsResponseEvent { pub auth_statuses: std::collections::HashMap, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema, TS)] #[serde(rename_all = "snake_case")] #[ts(rename_all = "snake_case")] pub enum McpAuthStatus { @@ -1282,12 +1297,12 @@ impl fmt::Display for McpAuthStatus { } /// Response payload for `Op::ListCustomPrompts`. -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct ListCustomPromptsResponseEvent { pub custom_prompts: Vec, } -#[derive(Debug, Default, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Default, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct SessionConfiguredEvent { /// Name left as session_id instead of conversation_id for backwards compatibility. pub session_id: ConversationId, @@ -1314,7 +1329,9 @@ pub struct SessionConfiguredEvent { } /// User's decision in response to an ExecApprovalRequest. -#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Display, TS)] +#[derive( + Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, Display, JsonSchema, TS, +)] #[serde(rename_all = "snake_case")] pub enum ReviewDecision { /// User has approved this command and the agent should execute it. @@ -1335,7 +1352,7 @@ pub enum ReviewDecision { Abort, } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum FileChange { Add { @@ -1350,7 +1367,7 @@ pub enum FileChange { }, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct Chunk { /// 1-based line index of the first line in the original file pub orig_index: u32, @@ -1358,12 +1375,12 @@ pub struct Chunk { pub inserted_lines: Vec, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)] pub struct TurnAbortedEvent { pub reason: TurnAbortReason, } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, TS)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] #[serde(rename_all = "snake_case")] pub enum TurnAbortReason { Interrupted,