From d66cf37d66f9728e67d091a7f38c08db58b0ba8d Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Fri, 17 Jul 2026 21:55:17 +0800 Subject: [PATCH 01/49] feat(acp): revive ACP server over WebSocket (#1260) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore the ACP server adapter from the auto-closed #1260, rebased onto main. Exposes OAB as an ACP server over WebSocket at `GET /acp`, gated by the `acp` feature + `OPENAB_ACP_ENABLED`. Prompts are bridged to `GatewayEvent` and replies streamed back through the existing pipeline. Also resolves the outstanding review finding on #1260: `serve()` built `AcpConfig::from_env()` twice (two independent registries) — now extracted once, matching `AppState::from_env()`. Co-Authored-By: Claude Opus 4.8 --- Cargo.lock | 1 + Cargo.toml | 3 +- crates/openab-gateway/Cargo.toml | 1 + .../openab-gateway/src/adapters/acp_server.rs | 633 ++++++++++++++++++ crates/openab-gateway/src/adapters/mod.rs | 2 + crates/openab-gateway/src/lib.rs | 44 ++ 6 files changed, 683 insertions(+), 1 deletion(-) create mode 100644 crates/openab-gateway/src/adapters/acp_server.rs diff --git a/Cargo.lock b/Cargo.lock index 74ddee92f..78afc7156 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2222,6 +2222,7 @@ dependencies = [ "aws-sdk-secretsmanager", "aws-sigv4", "base64", + "bytes", "chrono", "chrono-tz", "clap", diff --git a/Cargo.toml b/Cargo.toml index 4ed8f5be7..5e6d5b40d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ serenity = { version = "0.12", default-features = false, features = ["client", " default = ["discord", "slack", "secrets-aws", "agentcore", "config-s3", "pre-seed", "filestore"] # Opt-in: compile all gateway adapters into a single unified binary -unified = ["telegram", "line", "feishu", "googlechat", "wecom", "teams"] +unified = ["telegram", "line", "feishu", "googlechat", "wecom", "teams", "acp"] # Core adapters discord = ["dep:serenity", "openab-core/discord"] @@ -48,6 +48,7 @@ feishu = ["dep:openab-gateway", "dep:axum", "openab-gateway/feishu"] googlechat = ["dep:openab-gateway", "dep:axum", "openab-gateway/googlechat"] wecom = ["dep:openab-gateway", "dep:axum", "openab-gateway/wecom"] teams = ["dep:openab-gateway", "dep:axum", "openab-gateway/teams"] +acp = ["dep:openab-gateway", "dep:axum", "openab-gateway/acp"] [dev-dependencies] tempfile = "3.27.0" diff --git a/crates/openab-gateway/Cargo.toml b/crates/openab-gateway/Cargo.toml index 26ee00db9..8cd91e0ff 100644 --- a/crates/openab-gateway/Cargo.toml +++ b/crates/openab-gateway/Cargo.toml @@ -42,3 +42,4 @@ feishu = [] googlechat = [] wecom = [] teams = [] +acp = [] diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs new file mode 100644 index 000000000..69990f56c --- /dev/null +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -0,0 +1,633 @@ +//! ACP (Agent Client Protocol) Server adapter. +//! +//! Exposes OAB as an ACP-compliant server over WebSocket at `GET /acp`. +//! Any ACP client (Zed, JetBrains, desktop apps, web apps, CLIs) can connect +//! and interact with OAB's multi-agent platform using the standard protocol. +//! +//! Protocol flow: +//! Client connects via WebSocket → sends `initialize` → `session/new` → `session/prompt` +//! Server streams back `AgentMessageChunk` notifications, then the prompt response. +//! +//! Internally, prompts are converted to `GatewayEvent` and dispatched through OAB's +//! existing event pipeline. Replies (`GatewayReply`) are translated back into ACP +//! notifications and streamed to the client. + +use crate::schema::*; +use axum::extract::ws::{Message, WebSocket}; +use axum::extract::{Query, State, WebSocketUpgrade}; +use axum::http::StatusCode; +use axum::response::IntoResponse; +use futures_util::{SinkExt, StreamExt}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use std::collections::HashMap; +use std::sync::Arc; +use tokio::sync::mpsc; +use tracing::{debug, info, warn}; +use uuid::Uuid; + +// --------------------------------------------------------------------------- +// ACP Configuration +// --------------------------------------------------------------------------- + +pub struct AcpConfig { + pub auth_key: Option, +} + +impl AcpConfig { + pub fn from_env() -> Option { + let enabled = std::env::var("OPENAB_ACP_ENABLED") + .map(|v| v == "true" || v == "1") + .unwrap_or(false); + if !enabled { + return None; + } + let auth_key = std::env::var("OPENAB_ACP_AUTH_KEY").ok(); + if auth_key.is_none() { + warn!("OPENAB_ACP_AUTH_KEY not set — ACP endpoint is UNAUTHENTICATED"); + } + Some(Self { auth_key }) + } +} + +// --------------------------------------------------------------------------- +// ACP Session tracking +// --------------------------------------------------------------------------- + +/// Tracks an active ACP session. +struct AcpSession { + /// Channel ID used in GatewayEvent (maps replies back to this session) + channel_id: String, + /// Whether a prompt is currently in-flight for this session + busy: bool, +} + +pub enum ReplyChunk { + /// Incremental text snapshot (full text so far) + Text(String), + /// Agent finished responding + Done, +} + +/// Registry of active ACP sessions: channel_id → reply sender. +/// Uses std::sync::Mutex because all operations are fast CPU-bound +/// (insert/remove/get) and never hold the lock across .await. +pub type AcpReplyRegistry = Arc>>>; + +pub fn new_reply_registry() -> AcpReplyRegistry { + Arc::new(std::sync::Mutex::new(HashMap::new())) +} + +// --------------------------------------------------------------------------- +// JSON-RPC types (minimal subset for ACP) +// --------------------------------------------------------------------------- + +#[derive(Debug, Deserialize)] +struct JsonRpcRequest { + jsonrpc: String, + method: String, + #[serde(default)] + id: Option, + #[serde(default)] + params: Option, +} + +#[derive(Debug, Serialize)] +struct JsonRpcResponse { + jsonrpc: &'static str, + id: Value, + #[serde(skip_serializing_if = "Option::is_none")] + result: Option, + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, +} + +#[derive(Debug, Serialize)] +struct JsonRpcError { + code: i32, + message: String, +} + +#[derive(Debug, Serialize)] +struct JsonRpcNotification { + jsonrpc: &'static str, + method: String, + params: Value, +} + +impl JsonRpcResponse { + fn success(id: Value, result: Value) -> Self { + Self { + jsonrpc: "2.0", + id, + result: Some(result), + error: None, + } + } + + fn error(id: Value, code: i32, message: impl Into) -> Self { + Self { + jsonrpc: "2.0", + id, + result: None, + error: Some(JsonRpcError { + code, + message: message.into(), + }), + } + } +} + +// --------------------------------------------------------------------------- +// WebSocket upgrade handler: GET /acp +// --------------------------------------------------------------------------- + +pub async fn ws_upgrade( + State(state): State>, + query: Query>, + headers: axum::http::HeaderMap, + ws: WebSocketUpgrade, +) -> axum::response::Response { + // Auth: Bearer token from Authorization header or ?token= query param + let token = headers + .get("authorization") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.strip_prefix("Bearer ")) + .or_else(|| query.get("token").map(|s| s.as_str())); + + let expected = state.acp.as_ref().and_then(|c| c.auth_key.as_ref()); + if let Some(expected) = expected { + let valid = match token { + Some(t) => { + // Constant-time comparison to prevent timing attacks + use subtle::ConstantTimeEq; + t.as_bytes().ct_eq(expected.as_bytes()).into() + } + None => false, + }; + if !valid { + warn!("ACP WebSocket rejected: invalid or missing token"); + return StatusCode::UNAUTHORIZED.into_response(); + } + } + + ws.on_upgrade(move |socket| handle_acp_connection(state, socket)) +} + +// --------------------------------------------------------------------------- +// ACP Connection handler +// --------------------------------------------------------------------------- + +async fn handle_acp_connection(state: Arc, socket: WebSocket) { + let (mut ws_tx, mut ws_rx) = socket.split(); + let connection_id = format!("acp_conn_{}", Uuid::new_v4()); + + info!(connection = %connection_id, "ACP client connected"); + + // Session state for this connection + let sessions: Arc>> = + Arc::new(tokio::sync::Mutex::new(HashMap::new())); + let mut initialized = false; + + // Track spawned prompt tasks so we can abort on disconnect + let mut prompt_tasks: Vec> = Vec::new(); + + // Channel for sending messages back to the client + let (out_tx, mut out_rx) = mpsc::unbounded_channel::(); + + // Forward outbound messages to WebSocket + let send_task = tokio::spawn(async move { + while let Some(msg) = out_rx.recv().await { + if ws_tx.send(Message::Text(msg.into())).await.is_err() { + break; + } + } + }); + + // Process incoming messages + while let Some(Ok(msg)) = ws_rx.next().await { + let Message::Text(text) = msg else { + continue; + }; + + let req: JsonRpcRequest = match serde_json::from_str(&text) { + Ok(r) => r, + Err(e) => { + let err_resp = JsonRpcResponse::error( + Value::Null, + -32700, + format!("Parse error: {e}"), + ); + let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); + continue; + } + }; + + // Validate JSON-RPC version (spec requires "2.0") + if req.jsonrpc != "2.0" { + let err_resp = JsonRpcResponse::error( + req.id.clone().unwrap_or(Value::Null), + -32600, + "Invalid Request: jsonrpc must be \"2.0\"", + ); + let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); + continue; + } + + let id = req.id.clone().unwrap_or(Value::Null); + + match req.method.as_str() { + "initialize" => { + let resp = handle_initialize(&connection_id, &req); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + initialized = true; + } + "session/new" => { + if !initialized { + let resp = JsonRpcResponse::error(id, -32002, "Not initialized"); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + let resp = handle_session_new(&sessions, id.clone()).await; + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + } + "session/prompt" => { + if !initialized { + let resp = JsonRpcResponse::error(id, -32002, "Not initialized"); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + // session/prompt is async — spawn a task to handle streaming + let state_clone = state.clone(); + let sessions_clone = sessions.clone(); + let out_tx_clone = out_tx.clone(); + let handle = tokio::spawn(async move { + handle_session_prompt( + &state_clone, + &sessions_clone, + id, + req.params.as_ref(), + &out_tx_clone, + ) + .await; + }); + prompt_tasks.push(handle); + } + "session/cancel" => { + // TODO: implement cancellation in Phase 2 + let resp = JsonRpcResponse::success(id, json!({})); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + } + _ => { + let resp = JsonRpcResponse::error( + id, + -32601, + format!("Method not found: {}", req.method), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + } + } + + // Clean up finished tasks + prompt_tasks.retain(|h| !h.is_finished()); + } + + // --- Disconnect cleanup --- + // Abort any in-flight prompt tasks to prevent registry leaks + for handle in prompt_tasks { + handle.abort(); + } + + // Remove all sessions for this connection from the reply registry + if let Some(ref registry) = state.acp_reply_registry { + let sessions_guard = sessions.lock().await; + let channel_ids: Vec = sessions_guard + .values() + .map(|s| s.channel_id.clone()) + .collect(); + drop(sessions_guard); + + let mut reg = registry.lock().unwrap_or_else(|e| e.into_inner()); + for cid in &channel_ids { + reg.remove(cid); + } + debug!( + connection = %connection_id, + sessions_cleaned = channel_ids.len(), + "ACP connection cleanup complete" + ); + } + + send_task.abort(); + info!(connection = %connection_id, "ACP client disconnected"); +} + +// --------------------------------------------------------------------------- +// Method handlers +// --------------------------------------------------------------------------- + +fn handle_initialize(connection_id: &str, _req: &JsonRpcRequest) -> JsonRpcResponse { + let id = _req.id.clone().unwrap_or(Value::Null); + JsonRpcResponse::success( + id, + json!({ + "protocolVersion": "v1", + "connectionId": connection_id, + "agentCapabilities": { + "streaming": true, + "promptCapabilities": { + "image": false, + "audio": false, + "embeddedContext": false + } + }, + "agentInfo": { + "name": "openab", + "version": env!("CARGO_PKG_VERSION") + } + }), + ) +} + +async fn handle_session_new( + sessions: &Arc>>, + id: Value, +) -> JsonRpcResponse { + let session_id = format!("sess_{}", Uuid::new_v4()); + let channel_id = format!("acp_{}", Uuid::new_v4()); + + // Store session locally (reply channel is created lazily in session/prompt) + sessions.lock().await.insert( + session_id.clone(), + AcpSession { + channel_id, + busy: false, + }, + ); + + info!(session = %session_id, "ACP session created"); + + JsonRpcResponse::success( + id, + json!({ + "sessionId": session_id, + "models": { + "current": "openab", + "available": [ + {"id": "openab", "name": "OpenAB Default Agent"} + ] + } + }), + ) +} + +async fn handle_session_prompt( + state: &Arc, + sessions: &Arc>>, + id: Value, + params: Option<&Value>, + out_tx: &mpsc::UnboundedSender, +) { + // Extract sessionId and prompt from params + let (session_id, prompt_text) = match extract_prompt_params(params) { + Ok(v) => v, + Err(e) => { + let resp = JsonRpcResponse::error(id, -32602, e); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + return; + } + }; + + // Look up session and acquire busy lock + let channel_id = { + let mut guard = sessions.lock().await; + match guard.get_mut(&session_id) { + Some(s) => { + if s.busy { + // Reject concurrent prompts on the same session + let resp = JsonRpcResponse::error( + id, + -32001, + "Session busy: a prompt is already in progress", + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + return; + } + s.busy = true; + s.channel_id.clone() + } + None => { + let resp = JsonRpcResponse::error( + id, + -32602, + format!("Unknown session: {session_id}"), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + return; + } + } + }; + + // Create reply channel for this prompt and register it + let (reply_tx, mut reply_rx) = mpsc::unbounded_channel::(); + if let Some(ref registry) = state.acp_reply_registry { + registry + .lock() + .unwrap_or_else(|e| e.into_inner()) + .insert(channel_id.clone(), reply_tx); + } + + // Convert to GatewayEvent and dispatch + let event = GatewayEvent::new( + "acp", + ChannelInfo { + id: channel_id.clone(), + channel_type: "dm".into(), + thread_id: None, + }, + SenderInfo { + id: "acp_client".into(), + name: "acp_client".into(), + display_name: "ACP Client".into(), + is_bot: false, + }, + &prompt_text, + &format!("acpmsg_{}", Uuid::new_v4()), + Vec::new(), + ); + + // Send event through the broadcast channel + match serde_json::to_string(&event) { + Ok(json) => { + if state.event_tx.send(json).is_err() { + // No receivers — agent/core not connected + warn!("ACP: event_tx send failed — no agent connected"); + let resp = JsonRpcResponse::error( + id, + -32603, + "No agent backend connected", + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + // Release busy flag + if let Some(s) = sessions.lock().await.get_mut(&session_id) { + s.busy = false; + } + // Cleanup registry + if let Some(ref registry) = state.acp_reply_registry { + registry.lock().unwrap_or_else(|e| e.into_inner()).remove(&channel_id); + } + return; + } + } + Err(e) => { + warn!("ACP: failed to serialize event: {e}"); + let resp = JsonRpcResponse::error(id, -32603, "Internal error"); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + if let Some(s) = sessions.lock().await.get_mut(&session_id) { + s.busy = false; + } + return; + } + } + + info!(session = %session_id, channel = %channel_id, "ACP: prompt dispatched"); + + // Stream replies back as ACP notifications + let mut sent_len = 0usize; + let timeout = tokio::time::Duration::from_secs(180); + + loop { + match tokio::time::timeout(timeout, reply_rx.recv()).await { + Ok(Some(ReplyChunk::Text(full_text))) => { + // Send delta as AgentMessageChunk notification + let delta = if full_text.len() > sent_len { + &full_text[sent_len..] + } else { + continue; + }; + sent_len = full_text.len(); + + let notification = JsonRpcNotification { + jsonrpc: "2.0", + method: "session/notification".into(), + params: json!({ + "sessionId": session_id, + "update": { + "sessionUpdate": "agentMessageChunk", + "chunk": { + "content": {"type": "text", "text": delta} + } + } + }), + }; + let _ = out_tx.send(serde_json::to_string(¬ification).unwrap()); + } + Ok(Some(ReplyChunk::Done)) | Ok(None) => { + break; + } + Err(_) => { + warn!(session = %session_id, "ACP: prompt timed out waiting for reply"); + break; + } + } + } + + // Cleanup: remove from registry and release busy flag + if let Some(ref registry) = state.acp_reply_registry { + registry.lock().unwrap_or_else(|e| e.into_inner()).remove(&channel_id); + } + if let Some(s) = sessions.lock().await.get_mut(&session_id) { + s.busy = false; + } + + // Send the final response + let resp = JsonRpcResponse::success( + id, + json!({ + "sessionId": session_id, + "stopReason": "endTurn" + }), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); +} + +fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), String> { + let params = params.ok_or("Missing params")?; + let session_id = params + .get("sessionId") + .and_then(|v| v.as_str()) + .ok_or("Missing sessionId")? + .to_string(); + let prompt = params.get("prompt").ok_or("Missing prompt")?; + + // Prompt can be an array of content blocks or a simple string + let text = if let Some(arr) = prompt.as_array() { + arr.iter() + .filter_map(|block| { + if block.get("type").and_then(|t| t.as_str()) == Some("text") { + block.get("text").and_then(|t| t.as_str()) + } else { + None + } + }) + .collect::>() + .join("\n") + } else if let Some(s) = prompt.as_str() { + s.to_string() + } else { + return Err("Invalid prompt format".into()); + }; + + if text.trim().is_empty() { + return Err("Empty prompt".into()); + } + + Ok((session_id, text)) +} + +// --------------------------------------------------------------------------- +// Reply handler: called when GatewayReply arrives for an ACP session +// --------------------------------------------------------------------------- + +/// Process a GatewayReply destined for an ACP session. +/// Called from the unified bridge's reply dispatch logic. +pub async fn handle_reply(reply: &GatewayReply, registry: &AcpReplyRegistry) { + let key = reply.channel.id.as_str(); + if !key.starts_with("acp_") { + return; + } + + let full_text = reply.content.text.clone(); + // Skip placeholder/draft messages + if full_text == "…" || full_text == "draft" { + return; + } + + let tx = { + let map = registry.lock().unwrap_or_else(|e| e.into_inner()); + match map.get(key) { + Some(tx) => tx.clone(), + None => return, + } + }; + + match reply.command.as_deref() { + Some("edit_message") => { + // Streaming update — send as text snapshot + if tx.send(ReplyChunk::Text(full_text)).is_err() { + debug!(channel = key, "ACP reply send failed (client likely disconnected)"); + registry.lock().unwrap_or_else(|e| e.into_inner()).remove(key); + } + } + None | Some("send_message") => { + // Final message + let _ = tx.send(ReplyChunk::Text(full_text)); + let _ = tx.send(ReplyChunk::Done); + registry.lock().unwrap_or_else(|e| e.into_inner()).remove(key); + } + Some("add_reaction") | Some("remove_reaction") => { + // Reactions are agent state indicators — could map to notifications later + } + _ => {} + } +} diff --git a/crates/openab-gateway/src/adapters/mod.rs b/crates/openab-gateway/src/adapters/mod.rs index f58f870a2..ac7867766 100644 --- a/crates/openab-gateway/src/adapters/mod.rs +++ b/crates/openab-gateway/src/adapters/mod.rs @@ -12,3 +12,5 @@ pub mod googlechat; pub mod wecom; #[cfg(feature = "teams")] pub mod teams; +#[cfg(feature = "acp")] +pub mod acp_server; diff --git a/crates/openab-gateway/src/lib.rs b/crates/openab-gateway/src/lib.rs index bb59fb1b0..f7a92bf4d 100644 --- a/crates/openab-gateway/src/lib.rs +++ b/crates/openab-gateway/src/lib.rs @@ -58,6 +58,10 @@ pub struct AppState { pub googlechat_webhook_path: String, #[cfg(feature = "wecom")] pub wecom: Option, + #[cfg(feature = "acp")] + pub acp: Option, + #[cfg(feature = "acp")] + pub acp_reply_registry: Option, pub ws_token: Option, pub event_tx: broadcast::Sender, pub reply_token_cache: ReplyTokenCache, @@ -97,6 +101,10 @@ impl AppState { googlechat_webhook_path: "/webhook/googlechat".into(), #[cfg(feature = "wecom")] wecom: None, + #[cfg(feature = "acp")] + acp: None, + #[cfg(feature = "acp")] + acp_reply_registry: None, ws_token: None, event_tx, reply_token_cache: Arc::new(std::sync::Mutex::new(HashMap::new())), @@ -169,6 +177,12 @@ impl AppState { let wecom = adapters::wecom::WecomConfig::from_env() .map(adapters::wecom::WecomAdapter::new); + // ACP Server + #[cfg(feature = "acp")] + let acp = adapters::acp_server::AcpConfig::from_env(); + #[cfg(feature = "acp")] + let acp_reply_registry = acp.as_ref().map(|_| adapters::acp_server::new_reply_registry()); + let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(30)) .build() @@ -194,6 +208,10 @@ impl AppState { googlechat_webhook_path, #[cfg(feature = "wecom")] wecom, + #[cfg(feature = "acp")] + acp, + #[cfg(feature = "acp")] + acp_reply_registry, ws_token, event_tx, reply_token_cache: Arc::new(std::sync::Mutex::new(HashMap::new())), @@ -502,6 +520,13 @@ pub async fn serve(config: ServeConfig) -> anyhow::Result<()> { .route("/ws", get(ws_handler)) .route("/health", get(health)); + // ACP Server adapter + #[cfg(feature = "acp")] + if std::env::var("OPENAB_ACP_ENABLED").map(|v| v == "true" || v == "1").unwrap_or(false) { + info!("ACP server endpoint enabled at /acp"); + app = app.route("/acp", get(adapters::acp_server::ws_upgrade)); + } + // Telegram adapter #[cfg(feature = "telegram")] let telegram_bot_token = std::env::var("TELEGRAM_BOT_TOKEN").ok(); @@ -655,6 +680,15 @@ pub async fn serve(config: ServeConfig) -> anyhow::Result<()> { #[cfg(not(feature = "wecom"))] let wecom: Option<()> = None; + // ACP server — extract once so the config and its reply registry share a + // single from_env() result (a registry is only created when ACP is enabled). + #[cfg(feature = "acp")] + let acp = adapters::acp_server::AcpConfig::from_env(); + #[cfg(feature = "acp")] + let acp_reply_registry = acp + .as_ref() + .map(|_| adapters::acp_server::new_reply_registry()); + let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(30)) .build() @@ -684,6 +718,10 @@ pub async fn serve(config: ServeConfig) -> anyhow::Result<()> { googlechat_webhook_path, #[cfg(feature = "wecom")] wecom, + #[cfg(feature = "acp")] + acp, + #[cfg(feature = "acp")] + acp_reply_registry, ws_token, event_tx, reply_token_cache, @@ -905,6 +943,12 @@ async fn handle_oab_connection(state: Arc, socket: axum::extract::ws:: warn!("reply for wecom but adapter not configured"); } } + #[cfg(feature = "acp")] + "acp" => { + if let Some(ref registry) = state_for_recv.acp_reply_registry { + adapters::acp_server::handle_reply(&reply, registry).await; + } + } other => warn!(platform = other, "unknown reply platform"), } } From 8ab31b65a58b1aab11e14ec8cee5d35a6c3878c0 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Fri, 17 Jul 2026 22:04:46 +0800 Subject: [PATCH 02/49] feat(acp): ACP wire conformance, session/resume, streaming panic-safety MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align the ACP server to the official Agent Client Protocol (Schema v1.19.0) so standard ACP clients interoperate: - initialize: integer `protocolVersion: 1`, official `agentCapabilities` (`sessionCapabilities.resume`, `loadSession: false`, `promptCapabilities`), `authMethods: []`. - streaming: `session/update` notifications with `sessionUpdate: "agent_message_chunk"` and a `content` ContentBlock (was a custom `session/notification` + `chunk` wrapper). - stopReason: official snake_case (`end_turn` / `cancelled`); a backend timeout has no ACP stopReason and returns a JSON-RPC error instead. - session/cancel: one-way notification (no response) that ends the in-flight prompt with `stopReason: "cancelled"`. - session/resume: re-attach to a persisted session without replaying history (`session/load` is intentionally unsupported — the gateway keeps no replayable transcript; conversation state lives in the downstream agent). Also make delta streaming panic-safe: slice the reply snapshot with `str::get` instead of a byte index, so a boundary landing mid-codepoint (CJK / emoji) skips the frame instead of panicking. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 236 +++++++++++++----- 1 file changed, 172 insertions(+), 64 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 69990f56c..55c07009e 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -26,6 +26,10 @@ use tokio::sync::mpsc; use tracing::{debug, info, warn}; use uuid::Uuid; +/// ACP wire protocol MAJOR version (an integer), returned from `initialize`. +/// Tracks the official schema — see `docs/acp-official-methods.md`. +const ACP_PROTOCOL_VERSION: u32 = 1; + // --------------------------------------------------------------------------- // ACP Configuration // --------------------------------------------------------------------------- @@ -60,6 +64,11 @@ struct AcpSession { channel_id: String, /// Whether a prompt is currently in-flight for this session busy: bool, + /// Cancel signal for the in-flight prompt, if any. `session/cancel` fires + /// this so the streaming task stops gracefully and returns `stopReason: + /// "cancelled"` to the prompt's own request id (rather than hard-aborting + /// the task and orphaning that id). + cancel: Option>, } pub enum ReplyChunk { @@ -238,7 +247,7 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { match req.method.as_str() { "initialize" => { - let resp = handle_initialize(&connection_id, &req); + let resp = handle_initialize(&req); let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); initialized = true; } @@ -251,6 +260,15 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let resp = handle_session_new(&sessions, id.clone()).await; let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); } + "session/resume" => { + if !initialized { + let resp = JsonRpcResponse::error(id, -32002, "Not initialized"); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + let resp = handle_session_resume(&sessions, id.clone(), req.params.as_ref()).await; + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + } "session/prompt" => { if !initialized { let resp = JsonRpcResponse::error(id, -32002, "Not initialized"); @@ -274,9 +292,21 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { prompt_tasks.push(handle); } "session/cancel" => { - // TODO: implement cancellation in Phase 2 - let resp = JsonRpcResponse::success(id, json!({})); - let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + // Per ACP, session/cancel is a one-way NOTIFICATION — no response. + // Fire the session's cancel signal; the in-flight prompt observes + // it, cleans up, and returns stopReason:"cancelled" to the prompt's + // own request id. + let sess_key = req + .params + .as_ref() + .and_then(|p| p.get("sessionId")) + .and_then(|v| v.as_str()); + if let Some(k) = sess_key { + let notify = sessions.lock().await.get(k).and_then(|s| s.cancel.clone()); + if let Some(n) = notify { + n.notify_one(); + } + } } _ => { let resp = JsonRpcResponse::error( @@ -326,15 +356,21 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { // Method handlers // --------------------------------------------------------------------------- -fn handle_initialize(connection_id: &str, _req: &JsonRpcRequest) -> JsonRpcResponse { - let id = _req.id.clone().unwrap_or(Value::Null); +fn handle_initialize(req: &JsonRpcRequest) -> JsonRpcResponse { + let id = req.id.clone().unwrap_or(Value::Null); + // ACP initialize response. protocolVersion is an integer MAJOR version. + // We advertise `sessionCapabilities.resume` (we support session/resume) but + // NOT `loadSession` — the gateway cannot replay conversation history to the + // client (it lives inside the downstream agent CLI), so load is unsupported. JsonRpcResponse::success( id, json!({ - "protocolVersion": "v1", - "connectionId": connection_id, + "protocolVersion": ACP_PROTOCOL_VERSION, "agentCapabilities": { - "streaming": true, + "loadSession": false, + "sessionCapabilities": { + "resume": {} + }, "promptCapabilities": { "image": false, "audio": false, @@ -343,8 +379,10 @@ fn handle_initialize(connection_id: &str, _req: &JsonRpcRequest) -> JsonRpcRespo }, "agentInfo": { "name": "openab", + "title": "OpenAB", "version": env!("CARGO_PKG_VERSION") - } + }, + "authMethods": [] }), ) } @@ -353,32 +391,86 @@ async fn handle_session_new( sessions: &Arc>>, id: Value, ) -> JsonRpcResponse { - let session_id = format!("sess_{}", Uuid::new_v4()); - let channel_id = format!("acp_{}", Uuid::new_v4()); + // sessionId and channel_id share one uuid so channel_id is always + // re-derivable from a persisted sessionId (see session/resume). + let uuid = Uuid::new_v4(); + let session_id = format!("sess_{uuid}"); + let channel_id = format!("acp_{uuid}"); - // Store session locally (reply channel is created lazily in session/prompt) sessions.lock().await.insert( session_id.clone(), AcpSession { channel_id, busy: false, + cancel: None, }, ); info!(session = %session_id, "ACP session created"); - JsonRpcResponse::success( - id, - json!({ - "sessionId": session_id, - "models": { - "current": "openab", - "available": [ - {"id": "openab", "name": "OpenAB Default Agent"} - ] - } - }), - ) + // ACP session/new response is just { sessionId }. + JsonRpcResponse::success(id, json!({ "sessionId": session_id })) +} + +/// `session/resume` — re-attach to a session the client persisted, WITHOUT +/// replaying history (per ACP: the agent MUST NOT replay via session/update). +/// +/// The client re-presents its `sessionId`; we derive the same deterministic +/// `channel_id`, so the next prompt's GatewayEvent maps to the same core +/// `session_key` (`acp:`) and the existing conversation continues. +/// The core recovers the underlying agent session via its own persisted mapping +/// plus a downstream `session/load` (survives process restart within the agent's +/// retention / `session_ttl_hours`). Whether that succeeds is not observable +/// here — an expired session simply starts fresh, and the core prefixes its +/// first reply with a "Session expired" notice the client can surface. +/// +/// Security: `sessionId` is a server-minted, high-entropy capability; +/// `derive_channel_id` requires a well-formed `sess_`, keeping the channel +/// inside the `acp_` namespace and rejecting forged ids. +async fn handle_session_resume( + sessions: &Arc>>, + id: Value, + params: Option<&Value>, +) -> JsonRpcResponse { + let session_id = match params.and_then(|p| p.get("sessionId")).and_then(|v| v.as_str()) { + Some(s) => s.to_string(), + None => return JsonRpcResponse::error(id, -32602, "Missing sessionId"), + }; + + let channel_id = match derive_channel_id(&session_id) { + Some(cid) => cid, + None => { + return JsonRpcResponse::error( + id, + -32602, + "Invalid sessionId: expected the form sess_", + ); + } + }; + + sessions.lock().await.insert( + session_id.clone(), + AcpSession { + channel_id, + busy: false, + cancel: None, + }, + ); + + info!(session = %session_id, "ACP session resumed"); + + // ACP session/resume response is an empty object (no history replay). + JsonRpcResponse::success(id, json!({})) +} + +/// Derive the deterministic `channel_id` (`acp_`) from a client-supplied +/// `sessionId` (`sess_`). Returns `None` if malformed — the uuid must +/// parse, which keeps a resumed channel inside the `acp_` namespace and rejects +/// forged ids. +fn derive_channel_id(session_id: &str) -> Option { + let uuid = session_id.strip_prefix("sess_")?; + Uuid::parse_str(uuid).ok()?; + Some(format!("acp_{uuid}")) } async fn handle_session_prompt( @@ -398,6 +490,10 @@ async fn handle_session_prompt( } }; + // Cancel signal for this prompt; `session/cancel` fires it to stop the + // stream gracefully. + let cancel = Arc::new(tokio::sync::Notify::new()); + // Look up session and acquire busy lock let channel_id = { let mut guard = sessions.lock().await; @@ -414,6 +510,7 @@ async fn handle_session_prompt( return; } s.busy = true; + s.cancel = Some(cancel.clone()); s.channel_id.clone() } None => { @@ -492,62 +589,73 @@ async fn handle_session_prompt( info!(session = %session_id, channel = %channel_id, "ACP: prompt dispatched"); - // Stream replies back as ACP notifications + // Stream replies back as ACP `session/update` notifications. let mut sent_len = 0usize; let timeout = tokio::time::Duration::from_secs(180); + let mut stop_reason = "end_turn"; + let mut timed_out = false; loop { - match tokio::time::timeout(timeout, reply_rx.recv()).await { - Ok(Some(ReplyChunk::Text(full_text))) => { - // Send delta as AgentMessageChunk notification - let delta = if full_text.len() > sent_len { - &full_text[sent_len..] - } else { - continue; - }; - sent_len = full_text.len(); - - let notification = JsonRpcNotification { - jsonrpc: "2.0", - method: "session/notification".into(), - params: json!({ - "sessionId": session_id, - "update": { - "sessionUpdate": "agentMessageChunk", - "chunk": { - "content": {"type": "text", "text": delta} - } - } - }), - }; - let _ = out_tx.send(serde_json::to_string(¬ification).unwrap()); - } - Ok(Some(ReplyChunk::Done)) | Ok(None) => { + tokio::select! { + // session/cancel fired — stop gracefully. + _ = cancel.notified() => { + stop_reason = "cancelled"; break; } - Err(_) => { - warn!(session = %session_id, "ACP: prompt timed out waiting for reply"); - break; + recv = tokio::time::timeout(timeout, reply_rx.recv()) => { + match recv { + Ok(Some(ReplyChunk::Text(full_text))) => { + // Emit new text as an `agent_message_chunk` update. + // Slice via `get` (not byte-index `[..]`) so a `sent_len` + // that lands mid-codepoint — possible with CJK / 顏文字 / + // emoji if a snapshot is ever non-append — skips this frame + // instead of panicking; the next snapshot re-covers it. + let delta = match full_text.get(sent_len..) { + Some(d) if !d.is_empty() => d, + _ => continue, + }; + sent_len = full_text.len(); + + let notification = JsonRpcNotification { + jsonrpc: "2.0", + method: "session/update".into(), + params: json!({ + "sessionId": session_id, + "update": { + "sessionUpdate": "agent_message_chunk", + "content": {"type": "text", "text": delta} + } + }), + }; + let _ = out_tx.send(serde_json::to_string(¬ification).unwrap()); + } + Ok(Some(ReplyChunk::Done)) | Ok(None) => break, + Err(_) => { + warn!(session = %session_id, "ACP: prompt timed out waiting for reply"); + timed_out = true; + break; + } + } } } } - // Cleanup: remove from registry and release busy flag + // Cleanup: remove from registry, release busy flag, clear cancel signal. if let Some(ref registry) = state.acp_reply_registry { registry.lock().unwrap_or_else(|e| e.into_inner()).remove(&channel_id); } if let Some(s) = sessions.lock().await.get_mut(&session_id) { s.busy = false; + s.cancel = None; } - // Send the final response - let resp = JsonRpcResponse::success( - id, - json!({ - "sessionId": session_id, - "stopReason": "endTurn" - }), - ); + // Final response. A backend timeout has no ACP stopReason, so it is an error; + // otherwise return the turn's PromptResponse { stopReason }. + let resp = if timed_out { + JsonRpcResponse::error(id, -32603, "Timed out waiting for agent backend") + } else { + JsonRpcResponse::success(id, json!({ "stopReason": stop_reason })) + }; let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); } From 68d0748bc7b6bba3a2abe860320ee184296fbb92 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Fri, 17 Jul 2026 22:04:46 +0800 Subject: [PATCH 03/49] docs(acp): as-built Phase 1 ADR + official method coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Absorbs the pending ADR proposal from #1258 and adds two companion docs: - `docs/adr/acp-server-websocket.md` — the original proposal (@pahud), verbatim. - `docs/adr/acp-server-websocket-phase1.md` — the as-built Phase 1 ADR: the wire-conformant primitive surface, the `session/resume` (not `session/load`) decision with its rationale, and divergences from the proposal. - `docs/acp-official-methods.md` — the official ACP method surface pinned to Schema v1.19.0, with OpenAB's Phase 1 coverage and intentional non-support. Co-Authored-By: Claude Opus 4.8 --- docs/acp-official-methods.md | 87 ++++++++ docs/adr/acp-server-websocket-phase1.md | 122 ++++++++++++ docs/adr/acp-server-websocket.md | 252 ++++++++++++++++++++++++ 3 files changed, 461 insertions(+) create mode 100644 docs/acp-official-methods.md create mode 100644 docs/adr/acp-server-websocket-phase1.md create mode 100644 docs/adr/acp-server-websocket.md diff --git a/docs/acp-official-methods.md b/docs/acp-official-methods.md new file mode 100644 index 000000000..84db0ece0 --- /dev/null +++ b/docs/acp-official-methods.md @@ -0,0 +1,87 @@ +# ACP — Official Method Surface & OpenAB Coverage + +Reference list of the **official** Agent Client Protocol methods/notifications, and +how OpenAB's Phase 1 ACP server (`docs/adr/acp-server-websocket-phase1.md`) maps onto +them. Phase 1 targets **wire conformance** for the chat subset, so standard ACP +clients (Zed, JetBrains, …) interoperate. + +### Provenance / version pin + +This table is built against a specific ACP revision — pin it so future diffs are +traceable: + +| Field | Value | +|---|---| +| Spec docs | , | +| Governance repo | | +| **Schema release** | **v1.19.0** (latest on GitHub releases as of fetch date) | +| **Rust crate release** | **v1.4.0** | +| Fetched | 2026-07-17 | +| Wire `protocolVersion` | integer **`1`** (single MAJOR version, negotiated at `initialize`) | + +> When re-checking conformance later, bump this block to the new Schema/crate release +> and re-diff the tables below. + +Directions use the ACP roles: the **Agent** answers prompts (here, OpenAB); the +**Client** is the app/UI (browser, Zed, CLI). + +## Agent methods (Client → Agent, request/response) + +| Method | Purpose | OpenAB Phase 1 | +|---|---|---| +| `initialize` | Negotiate protocol + capabilities | ✅ conformant (`protocolVersion:1`, `agentCapabilities`, `authMethods:[]`) | +| `authenticate` | Authenticate via a declared auth method | ⛔ (we use a pre-connect token on the WS upgrade; `authMethods:[]`) | +| `logout` | Drop authenticated state | ⛔ | +| `session/new` | Create a new session | ✅ (`{cwd, mcpServers}` accepted; returns `{sessionId}`) | +| `session/load` | Load a session **with** history replay | ⛔ **by design** — `loadSession:false` (no upstream transcript to replay; see ADR §3) | +| `session/resume` | Resume a session **without** replay | ✅ (`{sessionId, cwd, mcpServers?}` → `{}`) | +| `session/prompt` | Process a user prompt | ✅ (streams `session/update`, returns `{stopReason}`) | +| `session/close` | Close a session | ⛔ (cleanup on WS disconnect) | +| `session/list` | List known sessions | ⛔ | +| `session/delete` | Delete a session | ⛔ | +| `session/set_config_option` | Set a session config option | ⛔ | +| `session/set_mode` | Set the session mode | ⛔ | + +## Notifications + +| Method | Direction | Purpose | OpenAB Phase 1 | +|---|---|---|---| +| `session/cancel` | Client → Agent | Cancel in-flight work (one-way, no response) | ✅ conformant (notification; prompt ends `stopReason:"cancelled"`) | +| `session/update` | Agent → Client | Stream session events | ✅ `agent_message_chunk` (text). Other variants (`tool_call`, `tool_call_update`, `plan`, …) are Phase 2 | +| `$/cancel_request` | Bidirectional | Cancel an in-flight JSON-RPC request | ⛔ | + +## Client methods (Agent → Client, request/response) + +The agent runs server-side with its own fs/terminal, so OpenAB does not call any of +these in Phase 1. + +| Method | Purpose | OpenAB Phase 1 | +|---|---|---| +| `session/request_permission` | Ask the client to approve a tool call | ⛔ (Phase 2) | +| `fs/read_text_file` / `fs/write_text_file` | Read/write a text file on the client | ⛔ | +| `terminal/create` / `output` / `wait_for_exit` / `kill` / `release` | Drive a client terminal | ⛔ | + +## Conformance status (Phase 1) + +The chat subset is **wire-conformant** with ACP Schema v1.19.0: + +- `initialize` → integer `protocolVersion:1`, official `agentCapabilities` shape + (`sessionCapabilities.resume`, `loadSession:false`, `promptCapabilities`), `authMethods:[]`. +- Streaming → `session/update` + `sessionUpdate:"agent_message_chunk"` + `content` ContentBlock. +- `stopReason` → official snake_case (`end_turn` / `cancelled`). +- `session/cancel` → one-way notification. +- Resume → `session/resume` (no replay), gated by `sessionCapabilities.resume`. + +### Intentional non-support (documented, not a gap to close in Phase 1) + +- **`session/load`** — needs an upstream conversation transcript OpenAB does not keep + (history lives in the downstream agent CLI). Advertised as `loadSession:false`. +- **`authenticate`/`logout`, ContentBlock non-text, tool-call updates, + `request_permission`, fs/terminal, session admin (`list`/`delete`/config/mode)** — + deferred to later phases per the roadmap. + +### To verify against a live client + +- Field-level exactness of `agentCapabilities` / `clientCapabilities` sub-objects and + the `ContentBlock` variants beyond `text`, by connecting a real ACP client (e.g. + Zed) and diffing the `initialize` + `session/prompt` exchange against the schema. diff --git a/docs/adr/acp-server-websocket-phase1.md b/docs/adr/acp-server-websocket-phase1.md new file mode 100644 index 000000000..56cc468e7 --- /dev/null +++ b/docs/adr/acp-server-websocket-phase1.md @@ -0,0 +1,122 @@ +# ADR: ACP Server over WebSocket — Phase 1 (as-built) + +- **Status:** Accepted +- **Date:** 2026-07-17 +- **Author:** @brettchien +- **Related:** [ADR: ACP Server with WebSocket Transport](./acp-server-websocket.md) (original proposal, @pahud) +- **Conformance:** official ACP Schema **v1.19.0** — see [acp-official-methods.md](../acp-official-methods.md) +- **Implementation:** this PR (revives and completes #1260) + +--- + +## 1. Context + +The original proposal ([acp-server-websocket.md](./acp-server-websocket.md)) defines +the full ACP-server vision across five phases. This ADR is the **as-built record of +Phase 1** — the concrete, **wire-conformant** primitive surface the implementation +ships and that future work should follow. + +Scope: a standard-ACP **1:1 streaming chat** endpoint for real ACP clients (browser, +desktop, IDE, CLI) over WebSocket. Not in Phase 1: tool calls / permissions, client +fs/terminal methods, multi-agent fan-out, Streamable HTTP. + +Design goal (per decision on 2026-07-17): **follow the official ACP guide** so +third-party ACP clients (Zed, JetBrains, …) interoperate — no custom method names. + +## 2. Decision — Phase 1 primitive surface (ACP-conformant) + +Transport: `GET /acp`, feature-gated `acp` + runtime `OPENAB_ACP_ENABLED`. Token auth +on the WS upgrade via timing-safe compare (`subtle::ConstantTimeEq`, +`OPENAB_ACP_AUTH_KEY`). JSON-RPC 2.0; non-`"2.0"` rejected with `-32600`. + +### Client → Agent (requests) + +| Method | Params | Result | +|---|---|---| +| `initialize` | `{ protocolVersion: 1, clientCapabilities?, clientInfo? }` | `{ protocolVersion: 1, agentCapabilities, agentInfo, authMethods: [] }` | +| `session/new` | `{ cwd, mcpServers }` | `{ sessionId }` | +| `session/resume` | `{ sessionId, cwd, mcpServers? }` | `{}` (no history replay) | +| `session/prompt` | `{ sessionId, prompt: [ContentBlock] }` | `{ stopReason }` | + +`agentCapabilities` advertises `sessionCapabilities.resume` (we support resume) and +`loadSession: false` (we cannot replay history — see §3). `promptCapabilities` are +all `false` in Phase 1 (text only). `protocolVersion` is the integer `1`. + +### Client → Agent (notification) + +| Method | Params | Effect | +|---|---|---| +| `session/cancel` | `{ sessionId }` | one-way; in-flight prompt ends with `stopReason:"cancelled"`. No response. | + +### Agent → Client (notification) + +- `session/update` with `update.sessionUpdate = "agent_message_chunk"` and + `update.content = { type:"text", text: }` — streamed reply text. Delta is + sliced char-boundary-safe (`str::get`, never byte-index) so CJK / 顏文字 / emoji + cannot panic the stream. +- Turn completion is the `session/prompt` **response** (`{ stopReason }`, correlated + to the request id), not a separate notification. `stopReason` ∈ `end_turn` / + `cancelled`. A backend timeout has no ACP stopReason, so it returns a JSON-RPC + error (`-32603`) instead. + +### Session ↔ core mapping + +- `sessionId = sess_` and `channel_id = acp_` share one uuid, so + `channel_id` is always re-derivable from a persisted `sessionId`. +- Prompts become a `GatewayEvent` (`platform:"acp"`, `channel:acp_`); core + keys continuity by `session_key = acp:`. + +## 3. Resume — why `session/resume`, not `session/load` + +ACP distinguishes `session/load` (agent **replays** history via `session/update`, +then responds) from `session/resume` (restores context, **MUST NOT** replay). We +implement **`session/resume`**, decided against `crates/openab-core/src/acp/pool.rs`: + +- The conversation history lives inside the **downstream** coding-agent CLI's session + (claude / codex / kiro). The core only persists a `thread_key → agent sessionId` + mapping — it does **not** hold a replayable upstream transcript. So the gateway + cannot satisfy `session/load`'s replay contract; `loadSession: false`. +- Continuation still works: on the next prompt, core recovers the underlying agent + session via its persisted mapping + downstream `session/load` (this survives a + process restart, within the agent's retention / `session_ttl_hours`, default 4h). +- `resume` therefore restores context without replay; the **client** keeps its own + transcript for display. `session/resume` returns `{}` immediately. + +Whether the core session is still alive is **not observable** at the gateway — an +expired session silently starts fresh, and the core prefixes its first reply with a +"Session expired" notice the client can surface. + +Security: `sessionId` is a server-minted, high-entropy capability; `session/resume` +requires a well-formed `sess_`, keeping the channel inside the `acp_` namespace +and rejecting forged ids. + +## 4. Divergences from the original proposal + +| Proposal (Phase 1) | As-built | Why | +|---|---|---| +| Add `agent-client-protocol` crate dep | removed — hand-rolled JSON-RPC | fewer deps; small surface | +| "Bearer token auth" | `subtle::ConstantTimeEq` + `OPENAB_ACP_AUTH_KEY` | timing-safe, no new dep | +| Resume in **Phase 3** | `session/resume` in **Phase 1** | core continuity is already channel-keyed + persisted, so a gateway-only change buys reconnect resume cheaply | + +## 5. Consequences & limits + +- **1:1 only** — reply registry is `channel_id → single reply_tx`; the delta stream + assumes one monotonic text. Multi-agent fan-out is Phase 4 (would corrupt this). +- **cwd / mcpServers** — accepted on `session/new` / `session/resume` for wire + conformance but not yet propagated into the agent (follow-up). +- **Emoji** — inline 顏文字 flow through as text; reaction emoji stay no-op in Phase 1. +- **Reconnect** — on WS disconnect the per-connection session map is dropped; the + client reconnects with `session/resume` + its persisted `sessionId`. + +## 6. Roadmap (from proposal; resume pulled into Phase 1) + +- **Phase 2** — tool calls: `session/update` variants `tool_call` / `tool_call_update`, + and `session/request_permission`; reaction emoji → updates +- **Phase 3** — `session/load` with history replay (needs an upstream transcript store) +- **Phase 4** — multi-agent fan-out +- **Phase 5** — Streamable HTTP (POST + SSE) on the same `/acp` + +## 7. References + +- Original proposal: [acp-server-websocket.md](./acp-server-websocket.md) +- Official method surface + coverage: [acp-official-methods.md](../acp-official-methods.md) diff --git a/docs/adr/acp-server-websocket.md b/docs/adr/acp-server-websocket.md new file mode 100644 index 000000000..672b5e419 --- /dev/null +++ b/docs/adr/acp-server-websocket.md @@ -0,0 +1,252 @@ +# ADR: ACP Server with WebSocket Transport + +- **Status:** Proposed +- **Date:** 2026-06-30 +- **Author:** @pahud +- **Related:** [ADR: Separate Binaries with Opt-In Unified Build](./unified-binary.md), [ADR: Multi-Platform Adapters](./multi-platform-adapters.md) +- **Implementation:** TBD + +--- + +## 1. Context & Problem + +OpenAB currently exposes agent capabilities through platform-specific adapters (Discord, Telegram, LINE, Teams, etc.) and a custom VTuber adapter that speaks OpenAI-compatible Chat Completions (PR #1234). Each adapter translates between the platform's protocol and OAB's internal `GatewayEvent`/`GatewayReply` schema. + +This creates several limitations: + +- **No standard protocol** — every new frontend (desktop app, VTuber skin, IDE plugin, CLI tool) requires a bespoke adapter +- **One-way translation** — the OpenAI-compatible endpoint is request/response only; the agent cannot initiate messages, request tool approval, or push structured state updates without a separate side-channel (Tier-2 WS) +- **No interoperability** — clients built for one agent platform cannot connect to OAB without custom integration work +- **Duplicated effort** — features like session management, tool call approval, and streaming are re-implemented per adapter + +Meanwhile, the **Agent Client Protocol (ACP)** has emerged as an industry standard for editor↔agent communication, backed by Zed, JetBrains, GitHub, and Block (Goose). ACP defines: + +- JSON-RPC 2.0 message format over stdio or WebSocket +- Session lifecycle (`initialize` → `session/new` → `session/prompt` → notifications) +- Bidirectional communication (agent can request permissions, push tool status) +- Streaming via notifications (`AgentMessageChunk`, `ToolCall`, `ToolCallUpdate`) +- Capability negotiation at connection time + +ACP's WebSocket transport RFD is in draft with reference implementations already shipping (zeph-acp, acp-ws-bridge). The official Rust crate [`agent-client-protocol`](https://crates.io/crates/agent-client-protocol) provides typed request/response/notification handling. + +### Why OAB is uniquely positioned + +Existing ACP servers (Anvil, Goose, codex-acp) are **local, single-agent** setups — they spawn one agent subprocess and drive it via stdio. No one is building a **remote, multi-agent ACP server** that: + +- Routes requests to different coding agents (Codex, Claude, Kiro, etc.) +- Manages agent orchestration and sub-agent pipelines +- Provides platform-level memory, MCP bridging, and tool policies +- Serves multiple concurrent clients over the network + +This is OAB's differentiation. + +--- + +## 2. Decision + +Implement an ACP-compliant server endpoint in the OpenAB unified binary, using WebSocket as the primary transport. The endpoint will be exposed at `GET /acp` with WebSocket upgrade, reusing the existing axum HTTP listener. + +### Architecture + +``` +ACP Clients + ├── IDE plugins (Zed, JetBrains) + ├── Desktop apps (AniCompanion, VTuber skins) + ├── Web apps (browser-based agent UI, web VTuber) + ├── CLI tools + └── Mobile apps + │ + │── GET /acp (Upgrade: websocket) — WSS from any environment + │── JSON-RPC over WebSocket (bidirectional) + │ +OpenAB Unified Binary + ├── src/acp_server.rs ← ACP JSON-RPC dispatch + ├── agent-client-protocol crate ← official Rust SDK + │ + ├── initialize → capability negotiation + ├── session/new → create OAB session, select agent + ├── session/prompt → dispatch to coding agent (or fan-out to multiple) + ├── session/notification → stream AgentMessageChunk, ToolCall, etc. + ├── requestPermission → tool approval flow + │ + └── Internal: GatewayEvent / GatewayReply (existing OAB machinery) + ├── agent container: Claude + ├── agent container: Codex + └── agent container: Kiro +``` + +### Client Scenarios + +ACP is transport-agnostic at the application layer — any environment that supports WebSocket can be a client: + +| Client Type | Example | Use Case | +|---|---|---| +| IDE plugin | Zed, JetBrains | Code editing with agent assist | +| Desktop app | AniCompanion | VTuber avatar driven by agent | +| Web app | Browser SPA (React/Vue) | Web-based agent UI, web VTuber with three-vrm | +| CLI | Custom shell tool | Headless automation, CI/CD | +| Mobile | iOS/Android app | On-the-go agent access | + +Web apps are particularly interesting — browsers natively support WebSocket, so a web-based frontend can connect directly to OAB's ACP endpoint without any bridge or adapter. This enables building rich agent UIs (including browser-rendered 3D VRM characters via three.js) that talk to the full OAB multi-agent platform. + +### Transport + +- **WebSocket** (primary): `GET /acp` with `Upgrade: websocket` header. Full-duplex, persistent connection. All JSON-RPC messages as WebSocket text frames. +- **Streamable HTTP** (future, optional): Same `/acp` endpoint, POST for client→server, GET+SSE for server→client. Deferred to Phase 2. +- **stdio** (not applicable): OAB is a network service, not a subprocess. + +### ACP Lifecycle Mapping + +| ACP Method | OAB Internal Action | +|---|---| +| `initialize` | Negotiate capabilities, return `connectionId` | +| `session/new` | Create session, resolve target agent from config/model param | +| `session/load` | Resume existing session from OAB session store | +| `session/prompt` | Convert to `GatewayEvent`, dispatch to agent | +| `session/cancel` | Cancel in-flight agent turn | +| `session/notification` (outbound) | Derived from `GatewayReply` — text chunks, tool calls, state | +| `requestPermission` (outbound) | When agent needs tool approval, prompt client | + +### Agent Routing + +The `model` field in `session/new` or `session/prompt` maps to OAB's agent pool: + +- `openab` (default) → OAB's configured default agent +- `codex::*` → Codex agent container +- `claude::*` → Claude agent container +- `kiro::*` → Kiro agent container + +This reuses OAB's existing multi-agent dispatch and session routing. + +### Multi-Agent Fan-Out (Future) + +One unique capability of OAB as an ACP server is fan-out to multiple agents with result aggregation. A single `session/prompt` can be dispatched to multiple agents in parallel: + +``` +ACP Client → session/prompt "review this code" + │ +OAB dispatcher ─┼── Claude → findings A + ├── Codex → findings B + └── Kiro → findings C + │ + aggregate → merged result → AgentMessageChunk stream back to client +``` + +This is analogous to how OAB's 法師 team currently reviews PRs (multiple agents review in parallel, results are synthesized). With ACP, this multi-agent orchestration becomes accessible to any client — not just Discord. + +Modes: +- **Single agent** (default): one session, one agent — same as today +- **Multi-session**: client opens N sessions to N agents concurrently (ACP spec supports multiple sessions per connection) +- **Fan-out aggregate**: OAB internally dispatches to multiple agents, returns a unified response (requires OAB-level orchestration logic) + +### Feature Flag + +```toml +[features] +unified = ["telegram", "line", "feishu", "googlechat", "wecom", "teams", "vtuber", "acp"] +acp = ["dep:agent-client-protocol", "dep:openab-gateway", "dep:axum"] +``` + +Enable with `OPENAB_ACP_ENABLED=true`. Auth via `OPENAB_ACP_AUTH_KEY` (Bearer token on WebSocket upgrade). + +--- + +## 3. Consequences + +### Positive + +- **Any ACP client connects to OAB** — Zed, JetBrains, desktop apps (AniCompanion), custom CLIs, bots +- **Standard protocol** — no more bespoke adapters for each new frontend +- **Bidirectional by design** — agent can request permission, push notifications, initiate conversations +- **Rich tool visibility** — clients get structured `ToolCall`/`ToolCallUpdate` events, not just flattened text +- **Session persistence** — clients can disconnect and resume via `session/load` +- **Ecosystem leverage** — official SDKs in Rust, TypeScript, Python, Kotlin, Java; no custom client libraries needed +- **VTuber superseded** — ACP subsumes both Tier-1 (streaming) and Tier-2 (state events) of the VTuber adapter; existing VTuber skins can migrate to ACP or continue using the OpenAI-compatible endpoint + +### Negative + +- **Dependency on external spec** — ACP is still evolving (WebSocket transport is "Draft" status); we may need to track spec changes +- **Complexity** — adds another endpoint to the unified binary alongside existing adapters +- **Not all clients speak ACP yet** — VTuber skins (AniCompanion, Open-LLM-VTuber) currently only speak OpenAI Chat Completions; adoption requires upstream PRs or an ACP→OpenAI bridge mode + +### Neutral + +- Existing platform adapters (Discord, Telegram, etc.) are unaffected — they continue using the internal gateway protocol +- The OpenAI-compatible VTuber endpoint can coexist as a simpler alternative for clients that don't need full ACP capabilities + +--- + +## 4. Alternatives Considered + +### A. Custom WebSocket protocol (rejected) + +Design our own JSON-over-WebSocket protocol for VTuber/desktop clients. + +**Why rejected:** Reinvents what ACP already standardizes. No ecosystem leverage, no existing SDKs, no interop with editors. More maintenance burden. + +### B. OpenAI Realtime API (rejected) + +Adopt OpenAI's Realtime API WebSocket protocol. + +**Why rejected:** Designed for voice/multimodal streaming, not agent↔client tool use. Missing session management, tool approval flows, and capability negotiation. Proprietary. + +### C. MCP Streamable HTTP only (rejected) + +Use MCP's transport layer for client communication. + +**Why rejected:** MCP is for agent↔tool communication (agent calls tools on MCP servers), not client↔agent. Different abstraction level. ACP already builds on top of MCP where appropriate. + +### D. Keep adapter-per-frontend approach (rejected) + +Continue building bespoke adapters (VTuber, future desktop app, future CLI). + +**Why rejected:** Doesn't scale. Each adapter re-implements session management, streaming, tool display. ACP gives us one implementation that works for all frontends. + +--- + +## 5. Implementation Plan + +### Phase 1: Core ACP Server (MVP) + +- Add `agent-client-protocol` crate dependency +- Implement WebSocket upgrade at `GET /acp` +- `initialize` / `session/new` / `session/prompt` / `session/cancel` +- Map `GatewayReply` to `AgentMessageChunk` notifications +- Bearer token auth on upgrade +- Feature-gated behind `acp` + +### Phase 2: Tool Calls & Permissions + +- Forward agent tool calls as `ToolCall` notifications +- Implement `requestPermission` for dangerous operations +- `ToolCallUpdate` with status and file locations + +### Phase 3: Multi-Session & Resume + +- Support multiple sessions per connection +- `session/load` with conversation history replay +- Session persistence in OAB's existing session store + +### Phase 4: Multi-Agent Fan-Out + +- Fan-out a single prompt to multiple agents +- Aggregate results into a unified response +- Expose as a special `model: "openab::ensemble"` or similar + +### Phase 5: Streamable HTTP (optional) + +- Add HTTP transport (POST + SSE) on the same `/acp` endpoint +- For environments where WebSocket is not viable (serverless, aggressive proxies) + +--- + +## 6. References + +- [Agent Client Protocol Spec](https://agentclientprotocol.com) +- [ACP WebSocket Transport RFD](https://agentclientprotocol.com/rfds/streamable-http-websocket-transport) +- [Official Rust SDK](https://crates.io/crates/agent-client-protocol) +- [ACP GitHub Repo](https://github.com/agentclientprotocol/agent-client-protocol) (3.5k stars) +- [Goose ACP Implementation](https://block-goose.mintlify.app/advanced/acp-protocol) +- [Brokk Anvil](https://github.com/brokkai/anvil) — Rust ACP server (45K SLoC) +- [acp-ws-bridge](https://crates.io/crates/acp-ws-bridge) — WebSocket↔stdio bridge +- [PR #1234: VTuber Adapter](https://github.com/openabdev/openab/pull/1234) — current OpenAI-compatible approach From 0c099df16ec70677554222287980d53bf56416c6 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 00:04:49 +0800 Subject: [PATCH 04/49] feat(acp): serve /acp from the embedded `openab run` gateway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #1260 mounted the ACP endpoint only on the standalone `openab-gateway` binary (`serve()`). Fleet deployments run the unified binary's embedded gateway (`openab run`, main.rs) instead, which never called `serve()` — so `/acp` was unreachable there. Mount `/acp` on the embedded gateway too (gated by `OPENAB_ACP_ENABLED`), and route ACP replies back through the unified adapter's `dispatch_reply` (`platform == "acp"`). Also start the embedded HTTP server when ACP is enabled even if only non-webhook platforms (e.g. Discord, which the core connects to directly) are configured — otherwise the listener never binds. Seed the `acp` platform into the gateway trust registry so its identity gating honours `GATEWAY_ALLOW_ALL_USERS` / `GATEWAY_ALLOWED_USERS` (the ACP sender id is `acp_client`); without this the acp platform defaulted to deny-all and every prompt was rejected. Co-Authored-By: Claude Opus 4.8 --- docs/acp-official-methods.md | 15 ++++++++++----- docs/adr/acp-server-websocket-phase1.md | 25 ++++++++++++++++++++++--- src/main.rs | 25 +++++++++++++++++++++++-- src/unified_adapter.rs | 6 ++++++ 4 files changed, 61 insertions(+), 10 deletions(-) diff --git a/docs/acp-official-methods.md b/docs/acp-official-methods.md index 84db0ece0..a5c2c4127 100644 --- a/docs/acp-official-methods.md +++ b/docs/acp-official-methods.md @@ -47,7 +47,7 @@ Directions use the ACP roles: the **Agent** answers prompts (here, OpenAB); the | Method | Direction | Purpose | OpenAB Phase 1 | |---|---|---|---| | `session/cancel` | Client → Agent | Cancel in-flight work (one-way, no response) | ✅ conformant (notification; prompt ends `stopReason:"cancelled"`) | -| `session/update` | Agent → Client | Stream session events | ✅ `agent_message_chunk` (text). Other variants (`tool_call`, `tool_call_update`, `plan`, …) are Phase 2 | +| `session/update` | Agent → Client | Stream session events | ✅ `agent_message_chunk` (text). Other variants (`agent_thought_chunk`, `tool_call`, `tool_call_update`, `plan`, `available_commands_update`, `usage_update`, …) are Phase 2 / not forwarded | | `$/cancel_request` | Bidirectional | Cancel an in-flight JSON-RPC request | ⛔ | ## Client methods (Agent → Client, request/response) @@ -80,8 +80,13 @@ The chat subset is **wire-conformant** with ACP Schema v1.19.0: `request_permission`, fs/terminal, session admin (`list`/`delete`/config/mode)** — deferred to later phases per the roadmap. -### To verify against a live client +### Live verification status -- Field-level exactness of `agentCapabilities` / `clientCapabilities` sub-objects and - the `ContentBlock` variants beyond `text`, by connecting a real ACP client (e.g. - Zed) and diffing the `initialize` + `session/prompt` exchange against the schema. +- **Verified end-to-end (2026-07-17)** — the chat subset (`initialize` → `session/new` + / `session/resume` → `session/prompt` → streamed `session/update` `agent_message_chunk` + → `{stopReason}`, plus `session/cancel`) drives a real backend (cursor-agent) and + streams replies to a WebSocket client (a Chrome side-panel extension + a raw + `ws` client). +- **Still unverified** — field-level exactness of `agentCapabilities` / + `clientCapabilities` sub-objects against a *third-party* ACP client (e.g. Zed), and + `ContentBlock` variants beyond `text` (image / audio / resource). diff --git a/docs/adr/acp-server-websocket-phase1.md b/docs/adr/acp-server-websocket-phase1.md index 56cc468e7..2da72567a 100644 --- a/docs/adr/acp-server-websocket-phase1.md +++ b/docs/adr/acp-server-websocket-phase1.md @@ -25,9 +25,28 @@ third-party ACP clients (Zed, JetBrains, …) interoperate — no custom method ## 2. Decision — Phase 1 primitive surface (ACP-conformant) -Transport: `GET /acp`, feature-gated `acp` + runtime `OPENAB_ACP_ENABLED`. Token auth -on the WS upgrade via timing-safe compare (`subtle::ConstantTimeEq`, -`OPENAB_ACP_AUTH_KEY`). JSON-RPC 2.0; non-`"2.0"` rejected with `-32600`. +Transport: `GET /acp`, feature-gated `acp` + runtime `OPENAB_ACP_ENABLED`. Mounted on +**both** the standalone `openab-gateway` binary (`serve()`) **and** the embedded +gateway of `openab run` (the unified binary) — so fleet deployments that run +`openab run` (not the standalone gateway) serve ACP too. The embedded HTTP server +starts whenever `OPENAB_ACP_ENABLED` is set (or any platform / `[gateway]` is +configured) — so an ACP-only deployment, or one whose only platform is Discord (which +the core connects to directly, without the webhook server), still binds the listener. +ACP replies are routed back via the unified adapter's `dispatch_reply` +(`platform == "acp"`). + +**Two independent auth layers:** + +1. **Transport** — token on the WS upgrade, timing-safe compare (`OPENAB_ACP_AUTH_KEY`; + unset ⇒ unauthenticated). +2. **Identity** — ACP events carry a fixed synthetic sender id `acp_client` and pass + through the gateway trust registry (the `acp` platform is seeded there alongside + telegram/line/…). Admit the sender with `GATEWAY_ALLOW_ALL_USERS=true` or + `GATEWAY_ALLOWED_USERS=acp_client`; otherwise every prompt is denied with a + "request-access" echo. (These must be **process** env on the broker, not + `[agent].env`.) + +JSON-RPC 2.0; non-`"2.0"` rejected with `-32600`. ### Client → Agent (requests) diff --git a/src/main.rs b/src/main.rs index ac54067e2..b4947c024 100644 --- a/src/main.rs +++ b/src/main.rs @@ -419,7 +419,7 @@ async fn main() -> anyhow::Result<()> { let allow_all_users = env_bool("GATEWAY_ALLOW_ALL_USERS", false); let allowed_users = env_set("GATEWAY_ALLOWED_USERS"); let mut reg = PlatformTrustConfigs::new(); - for platform in ["telegram", "line", "feishu", "wecom", "googlechat", "teams"] { + for platform in ["telegram", "line", "feishu", "wecom", "googlechat", "teams", "acp"] { reg.insert( platform, TrustConfig::new( @@ -910,7 +910,14 @@ async fn main() -> anyhow::Result<()> { let (_unified_handle, shared_unified_adapter) = { use openab_core::gateway::{process_gateway_event, GatewayEventContext}; - if unified_platform_enabled || cfg.telegram.is_some() { + // The ACP endpoint (mounted below) needs this embedded HTTP server too — + // start it even when only non-webhook platforms (e.g. Discord, which the + // core connects to directly) are configured. + let acp_enabled = cfg!(feature = "acp") + && std::env::var("OPENAB_ACP_ENABLED") + .map(|v| v == "true" || v == "1") + .unwrap_or(false); + if unified_platform_enabled || cfg.telegram.is_some() || acp_enabled { let listen_addr = std::env::var("GATEWAY_LISTEN").unwrap_or_else(|_| "0.0.0.0:8080".into()); @@ -1113,6 +1120,20 @@ async fn main() -> anyhow::Result<()> { ); } + // ACP server endpoint — mount on the embedded gateway so `openab run` + // (not just the standalone gateway binary) serves ACP over WebSocket. + #[cfg(feature = "acp")] + if std::env::var("OPENAB_ACP_ENABLED") + .map(|v| v == "true" || v == "1") + .unwrap_or(false) + { + info!("unified: ACP server endpoint enabled at /acp"); + app = app.route( + "/acp", + axum::routing::get(openab_gateway::adapters::acp_server::ws_upgrade), + ); + } + let app = app.with_state(gw_state.clone()); // Bridge task: receive events from adapters via event_tx, dispatch to core diff --git a/src/unified_adapter.rs b/src/unified_adapter.rs index d04d1ba7a..5179b0cd3 100644 --- a/src/unified_adapter.rs +++ b/src/unified_adapter.rs @@ -89,6 +89,12 @@ impl UnifiedGatewayAdapter { .await; } } + #[cfg(feature = "acp")] + "acp" => { + if let Some(ref registry) = self.gw_state.acp_reply_registry { + openab_gateway::adapters::acp_server::handle_reply(reply, registry).await; + } + } other => { tracing::warn!(platform = other, "unified adapter: unknown platform, cannot route reply"); } From c958331223ca7820b1138e58f260f10ebaccba63 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 12:11:00 +0800 Subject: [PATCH 05/49] docs(acp): add Phase 2 browser-control (MCP-over-ACP) design ADR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proposed design for the agent's LLM to autonomously operate the user's browser ("computer use" against the real, logged-in Chrome), exposed as MCP tools tunnelled over the existing `/acp` WebSocket (MCP-over-ACP): - extension runs the MCP server role over its outbound WS (MV3 can't listen); - OpenAB core proxies the browser tools to the in-pod agent (MCP client); - needs the agent→client request direction added, and generated (v1) types. Design only — not implemented. Linked from the Phase 1 roadmap. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-mcp-browser-control.md | 103 ++++++++++++++++++++++++ docs/adr/acp-server-websocket-phase1.md | 4 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 docs/adr/acp-mcp-browser-control.md diff --git a/docs/adr/acp-mcp-browser-control.md b/docs/adr/acp-mcp-browser-control.md new file mode 100644 index 000000000..77191e859 --- /dev/null +++ b/docs/adr/acp-mcp-browser-control.md @@ -0,0 +1,103 @@ +# ADR: Browser control via MCP-over-ACP (Phase 2, proposed) + +- **Status:** Proposed (design only — not implemented) +- **Date:** 2026-07-18 +- **Author:** @brettchien +- **Related:** [ACP Server over WebSocket — Phase 1 (as-built)](./acp-server-websocket-phase1.md), + [ACP Server with WebSocket Transport](./acp-server-websocket.md) (Phase 2: Tool Calls & + Permissions), [openab-agent MCP](./openab-agent-mcp.md) + +--- + +## 1. Context + +Phase 1 ships a 1:1 streaming chat ACP server at `GET /acp`; a browser side-panel +extension connects as an ACP client and drives an OpenAB agent. The next goal is for the +agent's **LLM to autonomously operate the user's browser** (click, read the DOM, navigate) +— i.e. browser "computer use", but targeting the user's real, logged-in Chrome session +rather than a sandbox VM. + +## 2. Decision + +Expose the browser as **MCP tools** and route them to the agent via **MCP-over-ACP**, +tunnelled over the **existing `/acp` WebSocket** the extension already holds. + +Why MCP (not a custom ACP `ExtRequest`): for the LLM to *autonomously* use browser +actions, they must appear in the agent's tool list (`tools/list`) so the model discovers +and calls them. A custom `ExtRequest` is a transport-level ACP extension the LLM never +sees as a tool — it only fits OpenAB-driven (non-LLM) operations. MCP is the standard way +agents receive tools, so browser actions must be MCP tools. + +### Roles +- **Extension = MCP server (role/logic).** It handles `tools/list` / `tools/call` and + executes DOM actions. An MV3 extension cannot open a *listening* socket, but MCP + server/client is about *who provides tools*, not who opens the connection — so the + extension serves MCP over the **outbound `/acp` WS it already opened**. This is the only + way a can't-listen extension can be a full MCP server. +- **OpenAB core = MCP proxy/aggregator.** OpenAB is a middlebox between two ACP + connections. It consumes the extension's tools from the upstream tunnel and re-exposes + them to the agent downstream (via `mcpServers`) so the LLM's `tools/list` sees them. +- **Agent = MCP client.** The agent (Claude / Codex / Cursor / Gemini …) is a subprocess + colocated in the OpenAB pod; it calls the tools over its in-pod ACP/MCP link. + +### Call route — the agent is in-pod; only the extension is remote +``` + REMOTE (user's browser) OPENAB POD (`openab run` — one process tree) + ┌──────────────────┐ ┌────────────────────────────────────────────────────┐ + │ browser extension│ │ ┌─────────┐ ┌───────────┐ ┌──────────────────┐ │ + │ = MCP SERVER │◀─/acp─▶│ │ gateway │──▶│ core │──▶│ agent CLI │ │ + │ browser tools │ WS │ │ /acp srv│ │ MCP proxy │ │ (subprocess) │ │ + └──────────────────┘ (only │ └─────────┘ └───────────┘ │ LLM (MCP client)│ │ + remote │ ▲ in-pod └──────────────────┘ │ + hop) │ └── stdio: ACP + MCP(mcpServers) ──┘ + └────────────────────────────────────────────────────┘ + + one tool call (LLM clicks a button); only ❸/❺ leave the pod: + ❶ LLM ─tools/call "browser.click"─▶ core (MCP proxy) [in-pod] + ❷ core ─▶ gateway ─❸ MCP-over-ACP──▶ extension [out of pod → remote] + ❹ extension runs it in the browser + ❺ result ──▶ gateway ─❻▶ core ─❼▶ LLM continues [remote → back in-pod] +``` + +### One WebSocket, multiplexed +The single `/acp` WS carries BOTH the ACP chat session (initialize / session.prompt / +session.update) AND the tunnelled MCP traffic (tools/list / tools/call / results), +distinguished by ACP method namespace. No second connection. + +## 3. Protocol gap to close first + +Phase 1 does only client→agent (prompt) and agent→client **notifications** (streaming +text). Browser control needs the **agent→client REQUEST** direction (request/response: +the agent asks the client to do X and awaits a result). The WS is already bidirectional; +`acp_server`'s dispatch loop must add the agent-initiated-request path. This is also the +point to move the wire types from hand-rolled to **generated** (see §5). + +## 4. Alternatives considered + +- **Custom `ExtRequest` per browser action** — rejected: not surfaced to the LLM as a + tool, so the model can't autonomously call it. Fits OpenAB-driven ops only. +- **Extension hosts a standalone MCP server (HTTP/SSE)** — rejected: MV3 extensions + cannot open a listening socket. +- **Anthropic-style `computer` tool (screenshot + pixel coords)** — subsumed: you can + expose `screenshot` + `click(x,y)` as MCP tools if desired, but DOM-semantic tools + (`click(selector)`, `read_dom`) are cheaper/more reliable and model-agnostic. + +## 5. Typing / dependencies + +- Bidirectional tool-call / client-method messages are exactly where hand-rolling breaks; + adopt **generated types** for the expanded surface. Use **v1** schema (stable; `v2` is + experimental and currently wire-identical). Prefer offline codegen (e.g. `typify`) to + emit plain-serde types — this avoids the `schemars`-heavy dependency tree the official + `agent-client-protocol-schema` crate pulls in for `JsonSchema` derives OpenAB doesn't + use at runtime. +- The MCP protocol machinery itself (handshake, tool lifecycle, tunnel framing) is NOT + just types — it needs an MCP implementation (e.g. `rmcp`, already used by + `openab-agent`), plus the ACP-tunnel transport glue. + +## 6. Relationship to Computer Use + +Same category as browser "computer use" (LLM autonomously drives a browser via a +perceive→act tool loop), but generalized: (a) targets the **user's real Chrome** (live, +logged-in), not a sandbox; (b) action surface is **extension-defined MCP tools** +(DOM-semantic or screenshot), not a model-specific tool; (c) **model-agnostic** — any +MCP-capable agent can use it. diff --git a/docs/adr/acp-server-websocket-phase1.md b/docs/adr/acp-server-websocket-phase1.md index 2da72567a..fc75bc4a7 100644 --- a/docs/adr/acp-server-websocket-phase1.md +++ b/docs/adr/acp-server-websocket-phase1.md @@ -130,7 +130,9 @@ and rejecting forged ids. ## 6. Roadmap (from proposal; resume pulled into Phase 1) - **Phase 2** — tool calls: `session/update` variants `tool_call` / `tool_call_update`, - and `session/request_permission`; reaction emoji → updates + and `session/request_permission`; reaction emoji → updates. Also enables browser + control (LLM operates the user's browser via MCP-over-ACP) — + see [Browser control via MCP-over-ACP](./acp-mcp-browser-control.md). - **Phase 3** — `session/load` with history replay (needs an upstream transcript store) - **Phase 4** — multi-agent fan-out - **Phase 5** — Streamable HTTP (POST + SSE) on the same `/acp` From d255e6f240c0761f0abe58fb320b738664ce8101 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 13:00:38 +0800 Subject: [PATCH 06/49] docs(acp): rename the Phase 1 ADR to "base" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reframe the as-built ACP-over-WS server ADR from "Phase 1" to "base" — it is the foundation later phases build on, not one numbered phase of many. Renames `acp-server-websocket-phase1.md` → `acp-server-websocket-base.md`, retitles, and updates the two referencing docs (method coverage + the Phase 2 browser-control ADR). Roadmap phase numbers (Phase 2–5) are unchanged. Co-Authored-By: Claude Opus 4.8 --- docs/acp-official-methods.md | 16 ++++++++-------- docs/adr/acp-mcp-browser-control.md | 6 +++--- ...-phase1.md => acp-server-websocket-base.md} | 18 +++++++++--------- 3 files changed, 20 insertions(+), 20 deletions(-) rename docs/adr/{acp-server-websocket-phase1.md => acp-server-websocket-base.md} (91%) diff --git a/docs/acp-official-methods.md b/docs/acp-official-methods.md index a5c2c4127..d593b33eb 100644 --- a/docs/acp-official-methods.md +++ b/docs/acp-official-methods.md @@ -1,8 +1,8 @@ # ACP — Official Method Surface & OpenAB Coverage Reference list of the **official** Agent Client Protocol methods/notifications, and -how OpenAB's Phase 1 ACP server (`docs/adr/acp-server-websocket-phase1.md`) maps onto -them. Phase 1 targets **wire conformance** for the chat subset, so standard ACP +how OpenAB's base ACP server (`docs/adr/acp-server-websocket-base.md`) maps onto +them. The base targets **wire conformance** for the chat subset, so standard ACP clients (Zed, JetBrains, …) interoperate. ### Provenance / version pin @@ -27,7 +27,7 @@ Directions use the ACP roles: the **Agent** answers prompts (here, OpenAB); the ## Agent methods (Client → Agent, request/response) -| Method | Purpose | OpenAB Phase 1 | +| Method | Purpose | OpenAB base | |---|---|---| | `initialize` | Negotiate protocol + capabilities | ✅ conformant (`protocolVersion:1`, `agentCapabilities`, `authMethods:[]`) | | `authenticate` | Authenticate via a declared auth method | ⛔ (we use a pre-connect token on the WS upgrade; `authMethods:[]`) | @@ -44,7 +44,7 @@ Directions use the ACP roles: the **Agent** answers prompts (here, OpenAB); the ## Notifications -| Method | Direction | Purpose | OpenAB Phase 1 | +| Method | Direction | Purpose | OpenAB base | |---|---|---|---| | `session/cancel` | Client → Agent | Cancel in-flight work (one-way, no response) | ✅ conformant (notification; prompt ends `stopReason:"cancelled"`) | | `session/update` | Agent → Client | Stream session events | ✅ `agent_message_chunk` (text). Other variants (`agent_thought_chunk`, `tool_call`, `tool_call_update`, `plan`, `available_commands_update`, `usage_update`, …) are Phase 2 / not forwarded | @@ -53,15 +53,15 @@ Directions use the ACP roles: the **Agent** answers prompts (here, OpenAB); the ## Client methods (Agent → Client, request/response) The agent runs server-side with its own fs/terminal, so OpenAB does not call any of -these in Phase 1. +these in the base. -| Method | Purpose | OpenAB Phase 1 | +| Method | Purpose | OpenAB base | |---|---|---| | `session/request_permission` | Ask the client to approve a tool call | ⛔ (Phase 2) | | `fs/read_text_file` / `fs/write_text_file` | Read/write a text file on the client | ⛔ | | `terminal/create` / `output` / `wait_for_exit` / `kill` / `release` | Drive a client terminal | ⛔ | -## Conformance status (Phase 1) +## Conformance status (base) The chat subset is **wire-conformant** with ACP Schema v1.19.0: @@ -72,7 +72,7 @@ The chat subset is **wire-conformant** with ACP Schema v1.19.0: - `session/cancel` → one-way notification. - Resume → `session/resume` (no replay), gated by `sessionCapabilities.resume`. -### Intentional non-support (documented, not a gap to close in Phase 1) +### Intentional non-support (documented, not a gap to close in the base) - **`session/load`** — needs an upstream conversation transcript OpenAB does not keep (history lives in the downstream agent CLI). Advertised as `loadSession:false`. diff --git a/docs/adr/acp-mcp-browser-control.md b/docs/adr/acp-mcp-browser-control.md index 77191e859..11802d77c 100644 --- a/docs/adr/acp-mcp-browser-control.md +++ b/docs/adr/acp-mcp-browser-control.md @@ -3,7 +3,7 @@ - **Status:** Proposed (design only — not implemented) - **Date:** 2026-07-18 - **Author:** @brettchien -- **Related:** [ACP Server over WebSocket — Phase 1 (as-built)](./acp-server-websocket-phase1.md), +- **Related:** [ACP Server over WebSocket — Base (as-built)](./acp-server-websocket-base.md), [ACP Server with WebSocket Transport](./acp-server-websocket.md) (Phase 2: Tool Calls & Permissions), [openab-agent MCP](./openab-agent-mcp.md) @@ -11,7 +11,7 @@ ## 1. Context -Phase 1 ships a 1:1 streaming chat ACP server at `GET /acp`; a browser side-panel +The base ships a 1:1 streaming chat ACP server at `GET /acp`; a browser side-panel extension connects as an ACP client and drives an OpenAB agent. The next goal is for the agent's **LLM to autonomously operate the user's browser** (click, read the DOM, navigate) — i.e. browser "computer use", but targeting the user's real, logged-in Chrome session @@ -66,7 +66,7 @@ distinguished by ACP method namespace. No second connection. ## 3. Protocol gap to close first -Phase 1 does only client→agent (prompt) and agent→client **notifications** (streaming +The base does only client→agent (prompt) and agent→client **notifications** (streaming text). Browser control needs the **agent→client REQUEST** direction (request/response: the agent asks the client to do X and awaits a result). The WS is already bidirectional; `acp_server`'s dispatch loop must add the agent-initiated-request path. This is also the diff --git a/docs/adr/acp-server-websocket-phase1.md b/docs/adr/acp-server-websocket-base.md similarity index 91% rename from docs/adr/acp-server-websocket-phase1.md rename to docs/adr/acp-server-websocket-base.md index fc75bc4a7..704bf1528 100644 --- a/docs/adr/acp-server-websocket-phase1.md +++ b/docs/adr/acp-server-websocket-base.md @@ -1,4 +1,4 @@ -# ADR: ACP Server over WebSocket — Phase 1 (as-built) +# ADR: ACP Server over WebSocket — Base (as-built) - **Status:** Accepted - **Date:** 2026-07-17 @@ -13,17 +13,17 @@ The original proposal ([acp-server-websocket.md](./acp-server-websocket.md)) defines the full ACP-server vision across five phases. This ADR is the **as-built record of -Phase 1** — the concrete, **wire-conformant** primitive surface the implementation +the base** — the concrete, **wire-conformant** primitive surface the implementation ships and that future work should follow. Scope: a standard-ACP **1:1 streaming chat** endpoint for real ACP clients (browser, -desktop, IDE, CLI) over WebSocket. Not in Phase 1: tool calls / permissions, client +desktop, IDE, CLI) over WebSocket. Not in the base: tool calls / permissions, client fs/terminal methods, multi-agent fan-out, Streamable HTTP. Design goal (per decision on 2026-07-17): **follow the official ACP guide** so third-party ACP clients (Zed, JetBrains, …) interoperate — no custom method names. -## 2. Decision — Phase 1 primitive surface (ACP-conformant) +## 2. Decision — the base primitive surface (ACP-conformant) Transport: `GET /acp`, feature-gated `acp` + runtime `OPENAB_ACP_ENABLED`. Mounted on **both** the standalone `openab-gateway` binary (`serve()`) **and** the embedded @@ -59,7 +59,7 @@ JSON-RPC 2.0; non-`"2.0"` rejected with `-32600`. `agentCapabilities` advertises `sessionCapabilities.resume` (we support resume) and `loadSession: false` (we cannot replay history — see §3). `promptCapabilities` are -all `false` in Phase 1 (text only). `protocolVersion` is the integer `1`. +all `false` in the base (text only). `protocolVersion` is the integer `1`. ### Client → Agent (notification) @@ -111,11 +111,11 @@ and rejecting forged ids. ## 4. Divergences from the original proposal -| Proposal (Phase 1) | As-built | Why | +| Proposal (the base) | As-built | Why | |---|---|---| | Add `agent-client-protocol` crate dep | removed — hand-rolled JSON-RPC | fewer deps; small surface | | "Bearer token auth" | `subtle::ConstantTimeEq` + `OPENAB_ACP_AUTH_KEY` | timing-safe, no new dep | -| Resume in **Phase 3** | `session/resume` in **Phase 1** | core continuity is already channel-keyed + persisted, so a gateway-only change buys reconnect resume cheaply | +| Resume in **Phase 3** | `session/resume` in **the base** | core continuity is already channel-keyed + persisted, so a gateway-only change buys reconnect resume cheaply | ## 5. Consequences & limits @@ -123,11 +123,11 @@ and rejecting forged ids. assumes one monotonic text. Multi-agent fan-out is Phase 4 (would corrupt this). - **cwd / mcpServers** — accepted on `session/new` / `session/resume` for wire conformance but not yet propagated into the agent (follow-up). -- **Emoji** — inline 顏文字 flow through as text; reaction emoji stay no-op in Phase 1. +- **Emoji** — inline 顏文字 flow through as text; reaction emoji stay no-op in the base. - **Reconnect** — on WS disconnect the per-connection session map is dropped; the client reconnects with `session/resume` + its persisted `sessionId`. -## 6. Roadmap (from proposal; resume pulled into Phase 1) +## 6. Roadmap (from proposal; resume pulled into the base) - **Phase 2** — tool calls: `session/update` variants `tool_call` / `tool_call_update`, and `session/request_permission`; reaction emoji → updates. Also enables browser From aef2555df31245cc3d3cf556e7479214cde12df0 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 13:27:19 +0800 Subject: [PATCH 07/49] docs(acp): rename browser ADR into the acp-server-websocket family MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `acp-mcp-browser-control.md` → `acp-server-websocket-mcp-browser.md` so all three ADRs share the `acp-server-websocket-*` prefix (proposal / base / mcp-browser) and group together. Updates the base ADR roadmap link. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 2 +- ...p-browser-control.md => acp-server-websocket-mcp-browser.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/adr/{acp-mcp-browser-control.md => acp-server-websocket-mcp-browser.md} (100%) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 704bf1528..625750a6b 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -132,7 +132,7 @@ and rejecting forged ids. - **Phase 2** — tool calls: `session/update` variants `tool_call` / `tool_call_update`, and `session/request_permission`; reaction emoji → updates. Also enables browser control (LLM operates the user's browser via MCP-over-ACP) — - see [Browser control via MCP-over-ACP](./acp-mcp-browser-control.md). + see [Browser control via MCP-over-ACP](./acp-server-websocket-mcp-browser.md). - **Phase 3** — `session/load` with history replay (needs an upstream transcript store) - **Phase 4** — multi-agent fan-out - **Phase 5** — Streamable HTTP (POST + SSE) on the same `/acp` diff --git a/docs/adr/acp-mcp-browser-control.md b/docs/adr/acp-server-websocket-mcp-browser.md similarity index 100% rename from docs/adr/acp-mcp-browser-control.md rename to docs/adr/acp-server-websocket-mcp-browser.md From 50e95b0a6cfca3754664ac41a62bb29f52b77b0c Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 13:30:34 +0800 Subject: [PATCH 08/49] docs(acp): consolidate base + browser ADRs to the re-scoped roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the original proposal's numbered Phase 2–5 roadmap with a re-scoped plan driven by the north-star goal (LLM operating the user's browser): - base §6: Critical path (agent→client requests, request_permission, MCP-over-ACP + core proxy, generated typed v1) / Optional / Not needed / Observability tiers. - Multi-agent "conversation" clarified: N independent OpenAB instances relayed by the client (a room) — client-side, not ACP fan-out. Fan-out removed. - Note OpenAB command parity is mostly free over ACP (text directives/slash are platform-agnostic). - Recommend an ACP trace mode first (know behavior, de-risk generated types). - Browser ADR de-phased (proposed north-star, not "Phase 2"). Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 58 ++++++++++++++++---- docs/adr/acp-server-websocket-mcp-browser.md | 9 +-- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 625750a6b..c58da685e 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -120,22 +120,60 @@ and rejecting forged ids. ## 5. Consequences & limits - **1:1 only** — reply registry is `channel_id → single reply_tx`; the delta stream - assumes one monotonic text. Multi-agent fan-out is Phase 4 (would corrupt this). + assumes one monotonic text. This matches ACP's 1:1 nature (one client ↔ one agent) and + is correct. Multi-agent "conversation" (Discord-style) is NOT fan-out and NOT an ACP + concern: it is N independent OpenAB instances, each its own `/acp` connection, relayed + by the client acting as the shared room (see §6, Not needed). +- **OpenAB command parity is mostly free** — control directives (`[[ws]]`, `[[model]]`, …) + and slash commands (`/reset`, `/model`, …) are message-text conventions parsed + platform-agnostically (`openab-core`), so they already work over ACP when the client + includes them in a prompt — no ACP-specific work required. A typed UI for them + (`authenticate` / `available_commands_update`) is an optional later nicety. - **cwd / mcpServers** — accepted on `session/new` / `session/resume` for wire conformance but not yet propagated into the agent (follow-up). - **Emoji** — inline 顏文字 flow through as text; reaction emoji stay no-op in the base. - **Reconnect** — on WS disconnect the per-connection session map is dropped; the client reconnects with `session/resume` + its persisted `sessionId`. -## 6. Roadmap (from proposal; resume pulled into the base) - -- **Phase 2** — tool calls: `session/update` variants `tool_call` / `tool_call_update`, - and `session/request_permission`; reaction emoji → updates. Also enables browser - control (LLM operates the user's browser via MCP-over-ACP) — - see [Browser control via MCP-over-ACP](./acp-server-websocket-mcp-browser.md). -- **Phase 3** — `session/load` with history replay (needs an upstream transcript store) -- **Phase 4** — multi-agent fan-out -- **Phase 5** — Streamable HTTP (POST + SSE) on the same `/acp` +## 6. Roadmap (re-scoped; not the original proposal's numbered phases) + +North star: the agent's LLM autonomously operating the user's real browser (generalized +"computer use") — see [MCP-over-ACP browser control](./acp-server-websocket-mcp-browser.md). + +### Critical path (next) — everything the browser goal requires +- **agent→client REQUEST direction** — the base does only client→agent + agent→client + *notifications*; browser/tool use needs the agent to send *requests* to the client and + await a result. The WS is already bidirectional; the dispatch loop must add this path. +- **`session/request_permission`** — tool-use approval. +- **MCP-over-ACP tunnel + OpenAB core as MCP proxy** — the extension exposes browser + tools (MCP server role over its outbound WS); core proxies them to the in-pod agent. +- **Generated typed wire types (v1)** — decided for the base: adopt offline codegen + (typify → plain serde, no `schemars` dep) rather than hand-rolling the expanded + bidirectional surface. Currently hand-rolled; migration planned (validate round-trip + against real traffic first). + +### Optional (as-needed, off the critical path) +- richer `session/update` variants: `tool_call` / `tool_call_update` (display), + `agent_thought_chunk` / `plan` / `available_commands_update` / `usage_update` +- `fs/*`, `terminal/*` (sibling agent→client capabilities) +- `ContentBlock` image / audio / resource (image only if screenshot-based browser tools) +- session admin: `session/close` / `list` / `delete`, `set_mode` / `set_config_option`, + `session/load` (history replay — needs an upstream transcript store) +- typed command UI: `authenticate`, `available_commands_update` advertisement +- **Streamable HTTP** transport (POST + SSE on `/acp`) — only for environments where + WebSocket is not viable (serverless, aggressive proxies); not needed for local/WS use +- multiple sessions per connection + +### Not needed (removed from scope) +- **Multi-agent fan-out / ensemble** — Discord-style multi-agent is N independent OpenAB + instances relayed by the client (a "room"): client-side orchestration, no ACP fan-out. + ACP is 1:1; fan-out would only produce a single-agent "ensemble" answer, which is not a + goal (you want to *see* the separate agents, not merge them). + +### Observability (recommended first, low-risk) +- An **ACP trace mode** (flag-gated, both directions/hops) to record real ACP traffic — + reveals the variant surface downstream agents actually emit, informs which of the + Optional variants to forward, and validates the generated-type round-trip. ## 7. References diff --git a/docs/adr/acp-server-websocket-mcp-browser.md b/docs/adr/acp-server-websocket-mcp-browser.md index 11802d77c..7757cde7d 100644 --- a/docs/adr/acp-server-websocket-mcp-browser.md +++ b/docs/adr/acp-server-websocket-mcp-browser.md @@ -1,11 +1,12 @@ -# ADR: Browser control via MCP-over-ACP (Phase 2, proposed) +# ADR: Browser control via MCP-over-ACP (proposed) -- **Status:** Proposed (design only — not implemented) +- **Status:** Proposed (design only — not implemented). North-star capability the base + builds toward; see the base ADR §6 roadmap "Critical path". - **Date:** 2026-07-18 - **Author:** @brettchien - **Related:** [ACP Server over WebSocket — Base (as-built)](./acp-server-websocket-base.md), - [ACP Server with WebSocket Transport](./acp-server-websocket.md) (Phase 2: Tool Calls & - Permissions), [openab-agent MCP](./openab-agent-mcp.md) + [ACP Server with WebSocket Transport](./acp-server-websocket.md) (original proposal), + [openab-agent MCP](./openab-agent-mcp.md) --- From 0096b2276d0661d52731e93498cb27adff5ea151 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 13:32:38 +0800 Subject: [PATCH 09/49] docs(acp): merge the typing/dependency decision into the base ADR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fold the standalone typing analysis into base ADR §7: hand-rolled now → generated (typify, serde-only, ~0 dep) for the expanded surface; full `agent-client-protocol` crate rejected (2nd async runtime), schema-only crate is +24 schemars-heavy deps; v1 only; round-trip caveat; hand-roll trivial / generate complex, downstream core client is the bigger ROI. Renumbers refs to §8. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 32 ++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index c58da685e..5223f4a94 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -175,7 +175,37 @@ North star: the agent's LLM autonomously operating the user's real browser (gene reveals the variant surface downstream agents actually emit, informs which of the Optional variants to forward, and validates the generated-type round-trip. -## 7. References +## 7. Typing & dependency decision (hand-rolled now → generated later) + +Both sides of OpenAB's ACP are currently **hand-rolled, untyped** (`serde_json::Value` + +manual string matching on `sessionUpdate` variants): the upstream server here (~740 +lines, chat only) and the downstream client in `openab-core/src/acp/` (`protocol.rs` + +`connection.rs`, ~1800 lines, many variants). Hand-rolling caused the exact conformance +bugs fixed during the base build (`agentMessageChunk`→`agent_message_chunk`, `stopReason` +snake_case, integer `protocolVersion: 1`). + +Options weighed for typing the wire: + +| Option | New deps | Verdict | +|---|---|---| +| Hand-roll (current) | 0 | Fine for the trivial chat subset; error-prone for the big bidirectional surface | +| Full `agent-client-protocol` crate | ~105 (incl. a 2nd async runtime, async-io/smol) | **Never** — connection/role machinery unneeded (we have our own WS + GatewayEvent bridge) | +| `agent-client-protocol-schema` (types) | **+24** (measured 376→400), schemars-dominated | schemars is for `JsonSchema` derive we don't use at runtime; `serde_with`/`strum` mandatory (no feature to drop); floor is fixed | +| **Offline codegen (typify) → committed serde-only `.rs`** | **~0 runtime** | **Chosen for the expanded surface** — typed conformance without the schemars tree | + +Notes: +- **v1 only.** `v2` is experimental (`unstable_protocol_v2`, adds `diffy`), currently + wire-identical to v1, "may change at any time". We negotiate `protocolVersion 1`. +- **Caveat:** ACP types lean on `serde_with` (MaybeUndefined tri-state, ~600 uses across + the crate's v1 source) — so a naive vendor-and-strip-`JsonSchema` is not clean, and + typify's plain-serde output must be **round-trip validated** (simple chat fields are + fine; advanced patterns need checking — hence the ACP trace mode in §6). +- **Rule:** hand-roll only the trivial; **generate the complex.** The switch point is the + bidirectional/MCP surface. Highest ROI if unifying: the downstream core client + (~1800 lines of manual variant matching), not this small upstream server. + +## 8. References - Original proposal: [acp-server-websocket.md](./acp-server-websocket.md) - Official method surface + coverage: [acp-official-methods.md](../acp-official-methods.md) +- MCP-over-ACP browser control: [acp-server-websocket-mcp-browser.md](./acp-server-websocket-mcp-browser.md) From e43d5774a54838707e90dca9df8227e32d76fd22 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 15:07:01 +0800 Subject: [PATCH 10/49] feat(acp): add OPENAB_ACP_TRACE frame tracing (both directions) Flag-gated (OPENAB_ACP_TRACE=1|true) logging of every JSON-RPC frame on the upstream client<->gateway hop, in both directions (dir="in"/"out"). Off by default. Traced at the two choke points: the inbound ws_rx read and the single outbound writer task. Captures real ACP traffic to validate the planned generated-type round-trip against what clients/agents actually emit. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 55c07009e..46dc83be0 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -54,6 +54,16 @@ impl AcpConfig { } } +/// Whether ACP frame tracing is on (`OPENAB_ACP_TRACE=1|true`). When set, every +/// JSON-RPC frame on the upstream client↔gateway hop is logged in both directions +/// (`dir="in"` / `dir="out"`). Off by default; enable to capture real traffic — e.g. +/// to validate the generated-type round-trip against what clients/agents actually emit. +pub(crate) fn acp_trace_enabled() -> bool { + std::env::var("OPENAB_ACP_TRACE") + .map(|v| v == "true" || v == "1") + .unwrap_or(false) +} + // --------------------------------------------------------------------------- // ACP Session tracking // --------------------------------------------------------------------------- @@ -193,6 +203,9 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { info!(connection = %connection_id, "ACP client connected"); + // Frame tracing (OPENAB_ACP_TRACE) — read once per connection. + let trace = acp_trace_enabled(); + // Session state for this connection let sessions: Arc>> = Arc::new(tokio::sync::Mutex::new(HashMap::new())); @@ -204,9 +217,14 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { // Channel for sending messages back to the client let (out_tx, mut out_rx) = mpsc::unbounded_channel::(); - // Forward outbound messages to WebSocket + // Forward outbound messages to WebSocket. Single choke point for every outbound + // frame, so trace here rather than at each send site. + let send_conn = connection_id.clone(); let send_task = tokio::spawn(async move { while let Some(msg) = out_rx.recv().await { + if trace { + info!(connection = %send_conn, dir = "out", frame = %msg, "ACP frame"); + } if ws_tx.send(Message::Text(msg.into())).await.is_err() { break; } @@ -219,6 +237,10 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { continue; }; + if trace { + info!(connection = %connection_id, dir = "in", frame = %text, "ACP frame"); + } + let req: JsonRpcRequest = match serde_json::from_str(&text) { Ok(r) => r, Err(e) => { From ff6818ceef8654c3cb4dc23162d82c22ba911d03 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 15:20:20 +0800 Subject: [PATCH 11/49] feat(acp): vendor + generate serde-only ACP v1 wire types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add crates/openab-gateway/src/adapters/acp_schema.rs, generated by cargo-typify 0.7.0 from the vendored ACP v1 JSON schema (schemas/acp-v1.schema.json, pinned to upstream schema.json @ eb88e992 / ACP Schema v1.19.0). Plain serde — no schemars/serde_with runtime dep. Feature-gated (acp), allow(dead_code) until acp_server migrates onto it. Full v1 surface is generated (one closed dep graph); the base wires only the chat subset. Round-trip of the chat subset against known-good wire was proven before committing (Initialize/NewSession/Prompt/StopReason/ContentBlock/ SessionNotification all exact; StopReason snake_case; ContentBlock untagged). Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/schemas/acp-v1.schema.json | 4667 ++++ .../openab-gateway/src/adapters/acp_schema.rs | 23203 ++++++++++++++++ crates/openab-gateway/src/adapters/mod.rs | 3 + 3 files changed, 27873 insertions(+) create mode 100644 crates/openab-gateway/schemas/acp-v1.schema.json create mode 100644 crates/openab-gateway/src/adapters/acp_schema.rs diff --git a/crates/openab-gateway/schemas/acp-v1.schema.json b/crates/openab-gateway/schemas/acp-v1.schema.json new file mode 100644 index 000000000..0a8301427 --- /dev/null +++ b/crates/openab-gateway/schemas/acp-v1.schema.json @@ -0,0 +1,4667 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Agent Client Protocol", + "anyOf": [ + { + "title": "Agent", + "description": "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility", + "type": "object", + "properties": { + "jsonrpc": { + "type": "string", + "enum": ["2.0"] + } + }, + "required": ["jsonrpc"], + "anyOf": [ + { + "title": "Request", + "allOf": [ + { + "$ref": "#/$defs/AgentRequest" + } + ] + }, + { + "title": "Response", + "allOf": [ + { + "$ref": "#/$defs/AgentResponse" + } + ] + }, + { + "title": "Notification", + "allOf": [ + { + "$ref": "#/$defs/AgentNotification" + } + ] + } + ] + }, + { + "title": "Client", + "description": "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility", + "type": "object", + "properties": { + "jsonrpc": { + "type": "string", + "enum": ["2.0"] + } + }, + "required": ["jsonrpc"], + "anyOf": [ + { + "title": "Request", + "allOf": [ + { + "$ref": "#/$defs/ClientRequest" + } + ] + }, + { + "title": "Response", + "allOf": [ + { + "$ref": "#/$defs/ClientResponse" + } + ] + }, + { + "title": "Notification", + "allOf": [ + { + "$ref": "#/$defs/ClientNotification" + } + ] + } + ] + }, + { + "title": "ProtocolLevel", + "description": "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility", + "type": "object", + "properties": { + "jsonrpc": { + "type": "string", + "enum": ["2.0"] + }, + "method": { + "description": "The notification method name.", + "type": "string" + }, + "params": { + "description": "Method-specific notification parameters.", + "anyOf": [ + { + "description": "General protocol-level notifications that all sides are expected to\nimplement.\n\nNotifications whose methods start with '$/' are messages which\nare protocol implementation dependent and might not be implementable in all\nclients or agents. For example if the implementation uses a single threaded\nsynchronous programming language then there is little it can do to react to\na `$/cancel_request` notification. If an agent or client receives\nnotifications starting with '$/' it is free to ignore the notification.\n\nNotifications do not expect a response.", + "anyOf": [ + { + "title": "CancelRequestNotification", + "description": "Cancels an ongoing request.\n\nThis is a notification sent by the side that sent a request to cancel that request.\n\nUpon receiving this notification, the receiver:\n\n1. MAY cancel the corresponding request activity and all nested activities\n2. MAY send any pending notifications.\n3. MUST send one of these responses for the original request:\n - Valid response with appropriate data (partial results or cancellation marker)\n - Error response with code `-32800` (Cancelled)\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)", + "allOf": [ + { + "$ref": "#/$defs/CancelRequestNotification" + } + ] + } + ] + }, + { + "type": "null" + } + ] + } + }, + "required": ["jsonrpc", "method"], + "x-docs-ignore": true + } + ], + "$defs": { + "AgentRequest": { + "description": "A JSON-RPC request object.", + "type": "object", + "properties": { + "id": { + "description": "The request id used to correlate the matching response.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "method": { + "description": "The method name to invoke.", + "type": "string" + }, + "params": { + "description": "Method-specific request parameters.", + "anyOf": [ + { + "description": "All possible requests that an agent can send to a client.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly.\n\nThis enum encompasses all method calls from agent to client.", + "anyOf": [ + { + "title": "WriteTextFileRequest", + "description": "Writes content to a text file in the client's file system.\n\nOnly available if the client advertises the `fs.writeTextFile` capability.\nAllows the agent to create or modify files within the client's environment.\n\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)", + "allOf": [ + { + "$ref": "#/$defs/WriteTextFileRequest" + } + ] + }, + { + "title": "ReadTextFileRequest", + "description": "Reads content from a text file in the client's file system.\n\nOnly available if the client advertises the `fs.readTextFile` capability.\nAllows the agent to access file contents within the client's environment.\n\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)", + "allOf": [ + { + "$ref": "#/$defs/ReadTextFileRequest" + } + ] + }, + { + "title": "RequestPermissionRequest", + "description": "Requests permission from the user for a tool call operation.\n\nCalled by the agent when it needs user authorization before executing\na potentially sensitive operation. The client should present the options\nto the user and return their decision.\n\nIf the client cancels the prompt turn via `session/cancel`, it MUST\nrespond to this request with `RequestPermissionOutcome::Cancelled`.\n\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)", + "allOf": [ + { + "$ref": "#/$defs/RequestPermissionRequest" + } + ] + }, + { + "title": "CreateTerminalRequest", + "description": "Executes a command in a new terminal\n\nOnly available if the `terminal` Client capability is set to `true`.\n\nReturns a `TerminalId` that can be used with other terminal methods\nto get the current output, wait for exit, and kill the command.\n\nThe `TerminalId` can also be used to embed the terminal in a tool call\nby using the `ToolCallContent::Terminal` variant.\n\nThe Agent is responsible for releasing the terminal by using the `terminal/release`\nmethod.\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", + "allOf": [ + { + "$ref": "#/$defs/CreateTerminalRequest" + } + ] + }, + { + "title": "TerminalOutputRequest", + "description": "Gets the terminal output and exit status\n\nReturns the current content in the terminal without waiting for the command to exit.\nIf the command has already exited, the exit status is included.\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", + "allOf": [ + { + "$ref": "#/$defs/TerminalOutputRequest" + } + ] + }, + { + "title": "ReleaseTerminalRequest", + "description": "Releases a terminal\n\nThe command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`\nto wait for the command to exit before releasing the terminal.\n\nAfter release, the `TerminalId` can no longer be used with other `terminal/*` methods,\nbut tool calls that already contain it, continue to display its output.\n\nThe `terminal/kill` method can be used to terminate the command without releasing\nthe terminal, allowing the Agent to call `terminal/output` and other methods.\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", + "allOf": [ + { + "$ref": "#/$defs/ReleaseTerminalRequest" + } + ] + }, + { + "title": "WaitForTerminalExitRequest", + "description": "Waits for the terminal command to exit and return its exit status\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", + "allOf": [ + { + "$ref": "#/$defs/WaitForTerminalExitRequest" + } + ] + }, + { + "title": "KillTerminalRequest", + "description": "Kills the terminal command without releasing the terminal\n\nWhile `terminal/release` will also kill the command, this method will keep\nthe `TerminalId` valid so it can be used with other methods.\n\nThis method can be helpful when implementing command timeouts which terminate\nthe command as soon as elapsed, and then get the final output so it can be sent\nto the model.\n\nNote: Call `terminal/release` when `TerminalId` is no longer needed.\n\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)", + "allOf": [ + { + "$ref": "#/$defs/KillTerminalRequest" + } + ] + }, + { + "title": "ExtMethodRequest", + "description": "Handles extension method requests from the agent.\n\nAllows the Agent to send an arbitrary request that is not part of the ACP spec.\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "allOf": [ + { + "$ref": "#/$defs/ExtRequest" + } + ] + } + ] + }, + { + "type": "null" + } + ] + } + }, + "required": ["id", "method"], + "x-docs-ignore": true + }, + "RequestId": { + "description": "JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null \\[1\\] and Numbers SHOULD NOT contain fractional parts \\[2\\]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n\\[1\\] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n\\[2\\] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions.", + "anyOf": [ + { + "title": "Null", + "description": "The JSON-RPC `null` request id.", + "type": "null" + }, + { + "title": "Number", + "description": "A numeric JSON-RPC request id.", + "type": "integer", + "format": "int64" + }, + { + "title": "Str", + "description": "A string JSON-RPC request id.", + "type": "string" + } + ] + }, + "WriteTextFileRequest": { + "description": "Request to write content to a text file.\n\nOnly available if the client supports the `fs.writeTextFile` capability.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "path": { + "description": "Absolute path to the file to write.", + "type": "string" + }, + "content": { + "description": "The text content to write to the file.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "path", "content"], + "x-side": "client", + "x-method": "fs/write_text_file" + }, + "SessionId": { + "description": "A unique identifier for a conversation session between a client and agent.\n\nSessions maintain their own context, conversation history, and state,\nallowing multiple independent interactions with the same agent.\n\nSee protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id)", + "type": "string" + }, + "ReadTextFileRequest": { + "description": "Request to read content from a text file.\n\nOnly available if the client supports the `fs.readTextFile` capability.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "path": { + "description": "Absolute path to the file to read.", + "type": "string" + }, + "line": { + "description": "Line number to start reading from (1-based).", + "type": ["integer", "null"], + "format": "uint32", + "minimum": 0, + "x-deserialize-default-on-error": true + }, + "limit": { + "description": "Maximum number of lines to read.", + "type": ["integer", "null"], + "format": "uint32", + "minimum": 0, + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "path"], + "x-side": "client", + "x-method": "fs/read_text_file" + }, + "RequestPermissionRequest": { + "description": "Request for user permission to execute a tool call.\n\nSent when the agent needs authorization before performing a sensitive operation.\n\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "toolCall": { + "description": "Details about the tool call requiring permission.", + "allOf": [ + { + "$ref": "#/$defs/ToolCallUpdate" + } + ] + }, + "options": { + "description": "Available permission options for the user to choose from.", + "type": "array", + "items": { + "$ref": "#/$defs/PermissionOption" + } + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "toolCall", "options"], + "x-side": "client", + "x-method": "session/request_permission" + }, + "ToolCallUpdate": { + "description": "An update to an existing tool call.\n\nUsed to report progress and results as tools execute. All fields except\nthe tool call ID are optional - only changed fields need to be included.\n\nSee protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating)", + "type": "object", + "properties": { + "toolCallId": { + "description": "The ID of the tool call being updated.", + "allOf": [ + { + "$ref": "#/$defs/ToolCallId" + } + ] + }, + "kind": { + "description": "Update the tool kind.", + "anyOf": [ + { + "$ref": "#/$defs/ToolKind" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "status": { + "description": "Update the execution status.", + "anyOf": [ + { + "$ref": "#/$defs/ToolCallStatus" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "title": { + "description": "Update the human-readable title.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "content": { + "description": "Replace the content collection.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/ToolCallContent" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "locations": { + "description": "Replace the locations collection.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/ToolCallLocation" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "rawInput": { + "description": "Update the raw input.", + "x-deserialize-default-on-error": true + }, + "rawOutput": { + "description": "Update the raw output.", + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["toolCallId"] + }, + "ToolCallId": { + "description": "Unique identifier for a tool call within a session.", + "type": "string" + }, + "ToolKind": { + "description": "Categories of tools that can be invoked.\n\nTool kinds help clients choose appropriate icons and optimize how they\ndisplay tool execution progress.\n\nSee protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating)", + "oneOf": [ + { + "description": "Reading files or data.", + "type": "string", + "const": "read" + }, + { + "description": "Modifying files or content.", + "type": "string", + "const": "edit" + }, + { + "description": "Removing files or data.", + "type": "string", + "const": "delete" + }, + { + "description": "Moving or renaming files.", + "type": "string", + "const": "move" + }, + { + "description": "Searching for information.", + "type": "string", + "const": "search" + }, + { + "description": "Running commands or code.", + "type": "string", + "const": "execute" + }, + { + "description": "Internal reasoning or planning.", + "type": "string", + "const": "think" + }, + { + "description": "Retrieving external data.", + "type": "string", + "const": "fetch" + }, + { + "description": "Switching the current session mode.", + "type": "string", + "const": "switch_mode" + }, + { + "description": "Other tool types (default).", + "type": "string", + "const": "other" + } + ] + }, + "ToolCallStatus": { + "description": "Execution status of a tool call.\n\nTool calls progress through different statuses during their lifecycle.\n\nSee protocol docs: [Status](https://agentclientprotocol.com/protocol/tool-calls#status)", + "oneOf": [ + { + "description": "The tool call hasn't started running yet because the input is either\nstreaming or we're awaiting approval.", + "type": "string", + "const": "pending" + }, + { + "description": "The tool call is currently running.", + "type": "string", + "const": "in_progress" + }, + { + "description": "The tool call completed successfully.", + "type": "string", + "const": "completed" + }, + { + "description": "The tool call failed with an error.", + "type": "string", + "const": "failed" + } + ] + }, + "ToolCallContent": { + "description": "Content produced by a tool call.\n\nTool calls can produce different types of content including\nstandard content blocks (text, images) or file diffs.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)", + "oneOf": [ + { + "description": "Standard content block (text, images, resources).", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "content" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/Content" + } + ] + }, + { + "description": "File modification shown as a diff.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "diff" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/Diff" + } + ] + }, + { + "description": "Embed a terminal created with `terminal/create` by its id.\n\nThe terminal must be added before calling `terminal/release`.\n\nSee protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "terminal" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/Terminal" + } + ] + } + ], + "discriminator": { + "propertyName": "type" + } + }, + "ContentBlock": { + "description": "Content blocks represent displayable information in the Agent Client Protocol.\n\nThey provide a structured way to handle various types of user-facing content—whether\nit's text from language models, images for analysis, or embedded resources for context.\n\nContent blocks appear in:\n- User prompts sent via `session/prompt`\n- Language model output streamed through `session/update` notifications\n- Progress updates and results from tool calls\n\nThis structure is compatible with the Model Context Protocol (MCP), enabling\nagents to seamlessly forward content from MCP tool outputs without transformation.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/content)", + "oneOf": [ + { + "description": "Text content. May be plain text or formatted with Markdown.\n\nAll agents MUST support text content blocks in prompts.\nClients SHOULD render this text as Markdown.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "text" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/TextContent" + } + ] + }, + { + "description": "Images for visual context or analysis.\n\nRequires the `image` prompt capability when included in prompts.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "image" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/ImageContent" + } + ] + }, + { + "description": "Audio data for transcription or analysis.\n\nRequires the `audio` prompt capability when included in prompts.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "audio" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/AudioContent" + } + ] + }, + { + "description": "References to resources that the agent can access.\n\nAll agents MUST support resource links in prompts.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "resource_link" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/ResourceLink" + } + ] + }, + { + "description": "Complete resource contents embedded directly in the message.\n\nPreferred for including context as it avoids extra round-trips.\n\nRequires the `embeddedContext` prompt capability when included in prompts.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "resource" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/EmbeddedResource" + } + ] + } + ], + "discriminator": { + "propertyName": "type" + } + }, + "Annotations": { + "description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed", + "type": "object", + "properties": { + "audience": { + "description": "Intended recipients for this content, such as the user or assistant.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/Role" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "lastModified": { + "description": "Timestamp indicating when the underlying resource was last modified.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "priority": { + "description": "Relative importance of this content when clients choose what to surface.", + "type": ["number", "null"], + "format": "double", + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "Role": { + "description": "The sender or recipient of messages and data in a conversation.", + "oneOf": [ + { + "description": "The assistant side of a conversation.", + "type": "string", + "const": "assistant" + }, + { + "description": "The user side of a conversation.", + "type": "string", + "const": "user" + } + ] + }, + "TextContent": { + "description": "Text provided to or from an LLM.", + "type": "object", + "properties": { + "annotations": { + "description": "Optional annotations that help clients decide how to display or route this content.", + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "text": { + "description": "Text payload carried by this content block.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["text"] + }, + "ImageContent": { + "description": "An image provided to or from an LLM.", + "type": "object", + "properties": { + "annotations": { + "description": "Optional annotations that help clients decide how to display or route this content.", + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "data": { + "description": "Base64-encoded media payload.", + "type": "string" + }, + "mimeType": { + "description": "MIME type describing the encoded media payload.", + "type": "string" + }, + "uri": { + "description": "URI associated with this resource or media payload.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["data", "mimeType"] + }, + "AudioContent": { + "description": "Audio provided to or from an LLM.", + "type": "object", + "properties": { + "annotations": { + "description": "Optional annotations that help clients decide how to display or route this content.", + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "data": { + "description": "Base64-encoded media payload.", + "type": "string" + }, + "mimeType": { + "description": "MIME type describing the encoded media payload.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["data", "mimeType"] + }, + "ResourceLink": { + "description": "A resource that the server is capable of reading, included in a prompt or tool call result.", + "type": "object", + "properties": { + "annotations": { + "description": "Optional annotations that help clients decide how to display or route this content.", + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "description": { + "description": "Optional human-readable details shown with this protocol object.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "mimeType": { + "description": "MIME type describing the encoded media payload.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "name": { + "description": "Human-readable name shown for this protocol object.", + "type": "string" + }, + "size": { + "description": "Optional size of the linked resource in bytes, if known.", + "type": ["integer", "null"], + "format": "int64", + "x-deserialize-default-on-error": true + }, + "title": { + "description": "Optional display title for end-user UI.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "uri": { + "description": "URI associated with this resource or media payload.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "uri"] + }, + "EmbeddedResourceResource": { + "description": "Resource content that can be embedded in a message.", + "anyOf": [ + { + "title": "TextResourceContents", + "description": "Text resource contents embedded directly in the message.", + "allOf": [ + { + "$ref": "#/$defs/TextResourceContents" + } + ] + }, + { + "title": "BlobResourceContents", + "description": "Binary resource contents embedded directly in the message.", + "allOf": [ + { + "$ref": "#/$defs/BlobResourceContents" + } + ] + } + ] + }, + "TextResourceContents": { + "description": "Text-based resource contents.", + "type": "object", + "properties": { + "mimeType": { + "description": "MIME type describing the encoded media payload.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "text": { + "description": "Text payload carried by this content block.", + "type": "string" + }, + "uri": { + "description": "URI associated with this resource or media payload.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["text", "uri"] + }, + "BlobResourceContents": { + "description": "Binary resource contents.", + "type": "object", + "properties": { + "blob": { + "description": "Base64-encoded bytes for a binary resource payload.", + "type": "string" + }, + "mimeType": { + "description": "MIME type describing the encoded media payload.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "uri": { + "description": "URI associated with this resource or media payload.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["blob", "uri"] + }, + "EmbeddedResource": { + "description": "The contents of a resource, embedded into a prompt or tool call result.", + "type": "object", + "properties": { + "annotations": { + "description": "Optional annotations that help clients decide how to display or route this content.", + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "resource": { + "description": "Embedded resource payload, either text or binary data.", + "allOf": [ + { + "$ref": "#/$defs/EmbeddedResourceResource" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["resource"] + }, + "Content": { + "description": "Standard content block (text, images, resources).", + "type": "object", + "properties": { + "content": { + "description": "The actual content block.", + "allOf": [ + { + "$ref": "#/$defs/ContentBlock" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["content"] + }, + "Diff": { + "description": "A diff representing file modifications.\n\nShows changes to files in a format suitable for display in the client UI.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)", + "type": "object", + "properties": { + "path": { + "description": "The absolute file path being modified.", + "type": "string" + }, + "oldText": { + "description": "The original content (None for new files).", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "newText": { + "description": "The new content after modification.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["path", "newText"] + }, + "TerminalId": { + "description": "Typed identifier used for terminal values on the wire.", + "type": "string" + }, + "Terminal": { + "description": "Embed a terminal created with `terminal/create` by its id.\n\nThe terminal must be added before calling `terminal/release`.\n\nSee protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)", + "type": "object", + "properties": { + "terminalId": { + "description": "Identifier of the terminal instance to embed in the content stream.", + "allOf": [ + { + "$ref": "#/$defs/TerminalId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["terminalId"] + }, + "ToolCallLocation": { + "description": "A file location being accessed or modified by a tool.\n\nEnables clients to implement \"follow-along\" features that track\nwhich files the agent is working with in real-time.\n\nSee protocol docs: [Following the Agent](https://agentclientprotocol.com/protocol/tool-calls#following-the-agent)", + "type": "object", + "properties": { + "path": { + "description": "The absolute file path being accessed or modified.", + "type": "string" + }, + "line": { + "description": "Optional line number within the file.", + "type": ["integer", "null"], + "format": "uint32", + "minimum": 0, + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["path"] + }, + "PermissionOption": { + "description": "An option presented to the user when requesting permission.", + "type": "object", + "properties": { + "optionId": { + "description": "Unique identifier for this permission option.", + "allOf": [ + { + "$ref": "#/$defs/PermissionOptionId" + } + ] + }, + "name": { + "description": "Human-readable label to display to the user.", + "type": "string" + }, + "kind": { + "description": "Hint about the nature of this permission option.", + "allOf": [ + { + "$ref": "#/$defs/PermissionOptionKind" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["optionId", "name", "kind"] + }, + "PermissionOptionId": { + "description": "Unique identifier for a permission option.", + "type": "string" + }, + "PermissionOptionKind": { + "description": "The type of permission option being presented to the user.\n\nHelps clients choose appropriate icons and UI treatment.", + "oneOf": [ + { + "description": "Allow this operation only this time.", + "type": "string", + "const": "allow_once" + }, + { + "description": "Allow this operation and remember the choice.", + "type": "string", + "const": "allow_always" + }, + { + "description": "Reject this operation only this time.", + "type": "string", + "const": "reject_once" + }, + { + "description": "Reject this operation and remember the choice.", + "type": "string", + "const": "reject_always" + } + ] + }, + "CreateTerminalRequest": { + "description": "Request to create a new terminal and execute a command.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "command": { + "description": "The command to execute.", + "type": "string" + }, + "args": { + "description": "Array of command arguments.", + "type": "array", + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "env": { + "description": "Environment variables for the command.", + "type": "array", + "items": { + "$ref": "#/$defs/EnvVariable" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "cwd": { + "description": "Working directory for the command. Must be an absolute path.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "outputByteLimit": { + "description": "Maximum number of output bytes to retain.\n\nWhen the limit is exceeded, the Client truncates from the beginning of the output\nto stay within the limit.\n\nThe Client MUST ensure truncation happens at a character boundary to maintain valid\nstring output, even if this means the retained output is slightly less than the\nspecified limit.", + "type": ["integer", "null"], + "format": "uint64", + "minimum": 0, + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "command"], + "x-side": "client", + "x-method": "terminal/create" + }, + "EnvVariable": { + "description": "An environment variable to set when launching an MCP server.", + "type": "object", + "properties": { + "name": { + "description": "The name of the environment variable.", + "type": "string" + }, + "value": { + "description": "The value to set for the environment variable.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "value"] + }, + "TerminalOutputRequest": { + "description": "Request to get the current output and status of a terminal.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "terminalId": { + "description": "The ID of the terminal to get output from.", + "allOf": [ + { + "$ref": "#/$defs/TerminalId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "terminalId"], + "x-side": "client", + "x-method": "terminal/output" + }, + "ReleaseTerminalRequest": { + "description": "Request to release a terminal and free its resources.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "terminalId": { + "description": "The ID of the terminal to release.", + "allOf": [ + { + "$ref": "#/$defs/TerminalId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "terminalId"], + "x-side": "client", + "x-method": "terminal/release" + }, + "WaitForTerminalExitRequest": { + "description": "Request to wait for a terminal command to exit.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "terminalId": { + "description": "The ID of the terminal to wait for.", + "allOf": [ + { + "$ref": "#/$defs/TerminalId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "terminalId"], + "x-side": "client", + "x-method": "terminal/wait_for_exit" + }, + "KillTerminalRequest": { + "description": "Request to kill a terminal without releasing it.", + "type": "object", + "properties": { + "sessionId": { + "description": "The session ID for this request.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "terminalId": { + "description": "The ID of the terminal to kill.", + "allOf": [ + { + "$ref": "#/$defs/TerminalId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "terminalId"], + "x-side": "client", + "x-method": "terminal/kill" + }, + "ExtRequest": { + "description": "Allows for sending an arbitrary request that is not part of the ACP spec.\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)" + }, + "AgentResponse": { + "description": "A JSON-RPC response object.", + "anyOf": [ + { + "title": "Result", + "description": "A successful JSON-RPC response.", + "type": "object", + "properties": { + "id": { + "description": "The id of the request this response answers.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "result": { + "description": "Method-specific response data.", + "anyOf": [ + { + "title": "InitializeResponse", + "description": "Successful result returned for a `initialize` request.", + "allOf": [ + { + "$ref": "#/$defs/InitializeResponse" + } + ] + }, + { + "title": "AuthenticateResponse", + "description": "Successful result returned for a `authenticate` request.", + "allOf": [ + { + "$ref": "#/$defs/AuthenticateResponse" + } + ] + }, + { + "title": "LogoutResponse", + "description": "Successful result returned for a `logout` request.", + "allOf": [ + { + "$ref": "#/$defs/LogoutResponse" + } + ] + }, + { + "title": "NewSessionResponse", + "description": "Successful result returned for a `session/new` request.", + "allOf": [ + { + "$ref": "#/$defs/NewSessionResponse" + } + ] + }, + { + "title": "LoadSessionResponse", + "description": "Successful result returned for a `session/load` request.", + "allOf": [ + { + "$ref": "#/$defs/LoadSessionResponse" + } + ] + }, + { + "title": "ListSessionsResponse", + "description": "Successful result returned for a `session/list` request.", + "allOf": [ + { + "$ref": "#/$defs/ListSessionsResponse" + } + ] + }, + { + "title": "DeleteSessionResponse", + "description": "Successful result returned for a `session/delete` request.", + "allOf": [ + { + "$ref": "#/$defs/DeleteSessionResponse" + } + ] + }, + { + "title": "ResumeSessionResponse", + "description": "Successful result returned for a `session/resume` request.", + "allOf": [ + { + "$ref": "#/$defs/ResumeSessionResponse" + } + ] + }, + { + "title": "CloseSessionResponse", + "description": "Successful result returned for a `session/close` request.", + "allOf": [ + { + "$ref": "#/$defs/CloseSessionResponse" + } + ] + }, + { + "title": "SetSessionModeResponse", + "description": "Successful result returned for a `session/set_mode` request.", + "allOf": [ + { + "$ref": "#/$defs/SetSessionModeResponse" + } + ] + }, + { + "title": "SetSessionConfigOptionResponse", + "description": "Successful result returned for a `session/set_config_option` request.", + "allOf": [ + { + "$ref": "#/$defs/SetSessionConfigOptionResponse" + } + ] + }, + { + "title": "PromptResponse", + "description": "Successful result returned for a `session/prompt` request.", + "allOf": [ + { + "$ref": "#/$defs/PromptResponse" + } + ] + }, + { + "title": "ExtMethodResponse", + "description": "Successful result returned by an extension method outside the core ACP method set.", + "allOf": [ + { + "$ref": "#/$defs/ExtResponse" + } + ] + } + ] + } + }, + "required": ["id", "result"] + }, + { + "title": "Error", + "description": "A failed JSON-RPC response.", + "type": "object", + "properties": { + "id": { + "description": "The id of the request this response answers.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "error": { + "description": "Method-specific error data.", + "allOf": [ + { + "$ref": "#/$defs/Error" + } + ] + } + }, + "required": ["id", "error"] + } + ], + "x-docs-ignore": true + }, + "InitializeResponse": { + "description": "Response to the `initialize` method.\n\nContains the negotiated protocol version and agent capabilities.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)", + "type": "object", + "properties": { + "protocolVersion": { + "description": "The protocol version the client specified if supported by the agent,\nor the latest protocol version supported by the agent.\n\nThe client should disconnect, if it doesn't support this version.", + "allOf": [ + { + "$ref": "#/$defs/ProtocolVersion" + } + ] + }, + "agentCapabilities": { + "description": "Capabilities supported by the agent.", + "x-deserialize-default-on-error": true, + "default": { + "loadSession": false, + "promptCapabilities": { + "image": false, + "audio": false, + "embeddedContext": false + }, + "mcpCapabilities": { + "http": false, + "sse": false + }, + "sessionCapabilities": {}, + "auth": {} + }, + "allOf": [ + { + "$ref": "#/$defs/AgentCapabilities" + } + ] + }, + "authMethods": { + "description": "Authentication methods supported by the agent.", + "type": "array", + "items": { + "$ref": "#/$defs/AuthMethod" + }, + "default": [], + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "agentInfo": { + "description": "Information about the Agent name and version sent to the Client.\n\nNote: in future versions of the protocol, this will be required.", + "anyOf": [ + { + "$ref": "#/$defs/Implementation" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["protocolVersion"], + "x-side": "agent", + "x-method": "initialize" + }, + "ProtocolVersion": { + "description": "Protocol version identifier.\n\nThis version is only bumped for breaking changes.\nNon-breaking changes should be introduced via capabilities.", + "type": "integer", + "format": "uint16", + "minimum": 0, + "maximum": 65535 + }, + "AgentCapabilities": { + "description": "Capabilities supported by the agent.\n\nAdvertised during initialization to inform the client about\navailable features and content types.\n\nSee protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)", + "type": "object", + "properties": { + "loadSession": { + "description": "Whether the agent supports `session/load`.", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "promptCapabilities": { + "description": "Prompt capabilities supported by the agent.", + "x-deserialize-default-on-error": true, + "default": { + "image": false, + "audio": false, + "embeddedContext": false + }, + "allOf": [ + { + "$ref": "#/$defs/PromptCapabilities" + } + ] + }, + "mcpCapabilities": { + "description": "MCP capabilities supported by the agent.", + "x-deserialize-default-on-error": true, + "default": { + "http": false, + "sse": false + }, + "allOf": [ + { + "$ref": "#/$defs/McpCapabilities" + } + ] + }, + "sessionCapabilities": { + "description": "Session lifecycle and prompt capabilities advertised by the agent.", + "x-deserialize-default-on-error": true, + "default": {}, + "allOf": [ + { + "$ref": "#/$defs/SessionCapabilities" + } + ] + }, + "auth": { + "description": "Authentication-related capabilities supported by the agent.", + "x-deserialize-default-on-error": true, + "default": {}, + "allOf": [ + { + "$ref": "#/$defs/AgentAuthCapabilities" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "PromptCapabilities": { + "description": "Prompt capabilities supported by the agent in `session/prompt` requests.\n\nBaseline agent functionality requires support for [`ContentBlock::Text`]\nand [`ContentBlock::ResourceLink`] in prompt requests.\n\nOther variants must be explicitly opted in to.\nCapabilities for different types of content in prompt requests.\n\nIndicates which content types beyond the baseline (text and resource links)\nthe agent can process.\n\nSee protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)", + "type": "object", + "properties": { + "image": { + "description": "Agent supports [`ContentBlock::Image`].", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "audio": { + "description": "Agent supports [`ContentBlock::Audio`].", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "embeddedContext": { + "description": "Agent supports embedded context in `session/prompt` requests.\n\nWhen enabled, the Client is allowed to include [`ContentBlock::Resource`]\nin prompt requests for pieces of context that are referenced in the message.", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "McpCapabilities": { + "description": "MCP capabilities supported by the agent", + "type": "object", + "properties": { + "http": { + "description": "Agent supports [`McpServer::Http`].", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "sse": { + "description": "Agent supports [`McpServer::Sse`].", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionCapabilities": { + "description": "Session capabilities supported by the agent.\n\nAs a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.\n\nOptionally, they **MAY** support other session methods and notifications by specifying additional capabilities.\n\nNote: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.\n\nSee protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)", + "type": "object", + "properties": { + "list": { + "description": "Whether the agent supports `session/list`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports listing sessions.", + "anyOf": [ + { + "$ref": "#/$defs/SessionListCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "delete": { + "description": "Whether the agent supports `session/delete`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports deleting sessions from `session/list`.", + "anyOf": [ + { + "$ref": "#/$defs/SessionDeleteCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "additionalDirectories": { + "description": "Whether the agent supports `additionalDirectories` on supported session lifecycle requests.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports `additionalDirectories` on\nsupported session lifecycle requests.\n\nAgents that also support `session/list` may return\n`SessionInfo.additionalDirectories` to report the complete ordered\nadditional-root list associated with a listed session.", + "anyOf": [ + { + "$ref": "#/$defs/SessionAdditionalDirectoriesCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "resume": { + "description": "Whether the agent supports `session/resume`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports resuming sessions.", + "anyOf": [ + { + "$ref": "#/$defs/SessionResumeCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "close": { + "description": "Whether the agent supports `session/close`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports closing sessions.", + "anyOf": [ + { + "$ref": "#/$defs/SessionCloseCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionListCapabilities": { + "description": "Capabilities for the `session/list` method.\n\nSupplying `{}` means the agent supports listing sessions.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionDeleteCapabilities": { + "description": "Capabilities for the `session/delete` method.\n\nSupplying `{}` means the agent supports deleting sessions from `session/list`.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionAdditionalDirectoriesCapabilities": { + "description": "Capabilities for additional session directories support.\n\nSupplying `{}` means the agent supports the `additionalDirectories` field on\nsupported session lifecycle requests. Agents that also support\n`session/list` may return `SessionInfo.additionalDirectories` to report the\ncomplete ordered additional-root list associated with a listed session.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionResumeCapabilities": { + "description": "Capabilities for the `session/resume` method.\n\nSupplying `{}` means the agent supports resuming sessions.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionCloseCapabilities": { + "description": "Capabilities for the `session/close` method.\n\nSupplying `{}` means the agent supports closing sessions.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "AgentAuthCapabilities": { + "description": "Authentication-related capabilities supported by the agent.", + "type": "object", + "properties": { + "logout": { + "description": "Whether the agent supports the logout method.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports the logout method.", + "anyOf": [ + { + "$ref": "#/$defs/LogoutCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "LogoutCapabilities": { + "description": "Logout capabilities supported by the agent.\n\nSupplying `{}` means the agent supports the logout method.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "AuthMethod": { + "description": "Describes an available authentication method.\n\nThe `type` field acts as the discriminator in the serialized JSON form.\nWhen no `type` is present, the method is treated as `agent`.", + "anyOf": [ + { + "title": "agent", + "description": "Agent handles authentication itself.\n\nThis is the default when no `type` is specified.", + "allOf": [ + { + "$ref": "#/$defs/AuthMethodAgent" + } + ] + } + ] + }, + "AuthMethodAgent": { + "description": "Agent handles authentication itself.\n\nThis is the default authentication method type.", + "type": "object", + "properties": { + "id": { + "description": "Unique identifier for this authentication method.", + "allOf": [ + { + "$ref": "#/$defs/AuthMethodId" + } + ] + }, + "name": { + "description": "Human-readable name of the authentication method.", + "type": "string" + }, + "description": { + "description": "Optional description providing more details about this authentication method.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["id", "name"] + }, + "AuthMethodId": { + "description": "Typed identifier used for auth method values on the wire.", + "type": "string" + }, + "Implementation": { + "description": "Metadata about the implementation of the client or agent.\nDescribes the name and version of an ACP implementation, with an optional\ntitle for UI representation.", + "type": "object", + "properties": { + "name": { + "description": "Intended for programmatic or logical use, but can be used as a display\nname fallback if title isn’t present.", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable\nand easily understood.\n\nIf not provided, the name should be used for display.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "version": { + "description": "Version of the implementation. Can be displayed to the user or used\nfor debugging or metrics purposes. (e.g. \"1.0.0\").", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "version"] + }, + "AuthenticateResponse": { + "description": "Response to the `authenticate` method.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "authenticate" + }, + "LogoutResponse": { + "description": "Response to the `logout` method.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "logout" + }, + "NewSessionResponse": { + "description": "Response from creating a new session.\n\nSee protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)", + "type": "object", + "properties": { + "sessionId": { + "description": "Unique identifier for the created session.\n\nUsed in all subsequent requests for this conversation.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "modes": { + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "anyOf": [ + { + "$ref": "#/$defs/SessionModeState" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "configOptions": { + "description": "Initial session configuration options if supported by the Agent.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/SessionConfigOption" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId"], + "x-side": "agent", + "x-method": "session/new" + }, + "SessionModeState": { + "description": "The set of modes and the one currently active.", + "type": "object", + "properties": { + "currentModeId": { + "description": "The current mode the Agent is in.", + "allOf": [ + { + "$ref": "#/$defs/SessionModeId" + } + ] + }, + "availableModes": { + "description": "The set of modes that the Agent can operate in", + "type": "array", + "items": { + "$ref": "#/$defs/SessionMode" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["currentModeId", "availableModes"] + }, + "SessionModeId": { + "description": "Unique identifier for a Session Mode.", + "type": "string" + }, + "SessionMode": { + "description": "A mode the agent can operate in.\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "type": "object", + "properties": { + "id": { + "description": "Stable identifier used to refer to this protocol object in later messages.", + "allOf": [ + { + "$ref": "#/$defs/SessionModeId" + } + ] + }, + "name": { + "description": "Human-readable name shown for this protocol object.", + "type": "string" + }, + "description": { + "description": "Optional human-readable details shown with this protocol object.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["id", "name"] + }, + "SessionConfigOption": { + "description": "A session configuration option selector and its current state.", + "type": "object", + "properties": { + "id": { + "description": "Unique identifier for the configuration option.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigId" + } + ] + }, + "name": { + "description": "Human-readable label for the option.", + "type": "string" + }, + "description": { + "description": "Optional description for the Client to display to the user.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "category": { + "description": "Optional semantic category for this option (UX only).", + "anyOf": [ + { + "$ref": "#/$defs/SessionConfigOptionCategory" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["id", "name"], + "oneOf": [ + { + "description": "Single-value selector (dropdown).", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "select" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/SessionConfigSelect" + } + ] + }, + { + "description": "Boolean on/off toggle.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "boolean" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/SessionConfigBoolean" + } + ] + } + ], + "discriminator": { + "propertyName": "type" + } + }, + "SessionConfigId": { + "description": "Unique identifier for a session configuration option.", + "type": "string" + }, + "SessionConfigOptionCategory": { + "description": "Semantic category for a session configuration option.\n\nThis is intended to help Clients distinguish broadly common selectors (e.g. model selector vs\nsession mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,\nplacement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown\ncategories gracefully.\n\nCategory names beginning with `_` are free for custom use, like other ACP extension methods.\nCategory names that do not begin with `_` are reserved for the ACP spec.", + "anyOf": [ + { + "description": "Session mode selector.", + "type": "string", + "const": "mode" + }, + { + "description": "Model selector.", + "type": "string", + "const": "model" + }, + { + "description": "Model-related configuration parameter.", + "type": "string", + "const": "model_config" + }, + { + "description": "Thought/reasoning level selector.", + "type": "string", + "const": "thought_level" + }, + { + "title": "other", + "description": "Unknown / uncategorized selector.", + "type": "string" + } + ] + }, + "SessionConfigValueId": { + "description": "Unique identifier for a session configuration option value.", + "type": "string" + }, + "SessionConfigSelectOptions": { + "description": "Possible values for a session configuration option.", + "anyOf": [ + { + "title": "Ungrouped", + "description": "A flat list of options with no grouping.", + "type": "array", + "items": { + "$ref": "#/$defs/SessionConfigSelectOption" + } + }, + { + "title": "Grouped", + "description": "A list of options grouped under headers.", + "type": "array", + "items": { + "$ref": "#/$defs/SessionConfigSelectGroup" + } + } + ] + }, + "SessionConfigSelectOption": { + "description": "A possible value for a session configuration option.", + "type": "object", + "properties": { + "value": { + "description": "Unique identifier for this option value.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigValueId" + } + ] + }, + "name": { + "description": "Human-readable label for this option value.", + "type": "string" + }, + "description": { + "description": "Optional description for this option value.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["value", "name"] + }, + "SessionConfigSelectGroup": { + "description": "A group of possible values for a session configuration option.", + "type": "object", + "properties": { + "group": { + "description": "Unique identifier for this group.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigGroupId" + } + ] + }, + "name": { + "description": "Human-readable label for this group.", + "type": "string" + }, + "options": { + "description": "The set of option values in this group.", + "type": "array", + "items": { + "$ref": "#/$defs/SessionConfigSelectOption" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["group", "name", "options"] + }, + "SessionConfigGroupId": { + "description": "Unique identifier for a session configuration option value group.", + "type": "string" + }, + "SessionConfigSelect": { + "description": "A single-value selector (dropdown) session configuration option payload.", + "type": "object", + "properties": { + "currentValue": { + "description": "The currently selected value.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigValueId" + } + ] + }, + "options": { + "description": "The set of selectable options.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigSelectOptions" + } + ] + } + }, + "required": ["currentValue", "options"] + }, + "SessionConfigBoolean": { + "description": "A boolean on/off toggle session configuration option payload.", + "type": "object", + "properties": { + "currentValue": { + "description": "The current value of the boolean option.", + "type": "boolean" + } + }, + "required": ["currentValue"] + }, + "LoadSessionResponse": { + "description": "Response from loading an existing session.", + "type": "object", + "properties": { + "modes": { + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "anyOf": [ + { + "$ref": "#/$defs/SessionModeState" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "configOptions": { + "description": "Initial session configuration options if supported by the Agent.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/SessionConfigOption" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "session/load" + }, + "ListSessionsResponse": { + "description": "Response from listing sessions.", + "type": "object", + "properties": { + "sessions": { + "description": "Array of session information objects", + "type": "array", + "items": { + "$ref": "#/$defs/SessionInfo" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "nextCursor": { + "description": "Opaque cursor token. If present, pass this in the next request's cursor parameter\nto fetch the next page. If absent, there are no more results.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessions"], + "x-side": "agent", + "x-method": "session/list" + }, + "SessionInfo": { + "description": "Information about a session returned by session/list", + "type": "object", + "properties": { + "sessionId": { + "description": "Unique identifier for the session", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "cwd": { + "description": "The working directory for this session. Must be an absolute path.", + "type": "string" + }, + "additionalDirectories": { + "description": "Additional workspace roots reported for this session. Each path must be absolute.\n\nWhen present, this is the complete ordered additional-root list reported\nby the Agent. Omitted and empty values are equivalent: the response\nreports no additional roots.", + "type": "array", + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "title": { + "description": "Human-readable title for the session", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "updatedAt": { + "description": "ISO 8601 timestamp of last activity", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "cwd"] + }, + "DeleteSessionResponse": { + "description": "Response from deleting a session.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "session/delete" + }, + "ResumeSessionResponse": { + "description": "Response from resuming an existing session.", + "type": "object", + "properties": { + "modes": { + "description": "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "anyOf": [ + { + "$ref": "#/$defs/SessionModeState" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "configOptions": { + "description": "Initial session configuration options if supported by the Agent.", + "type": ["array", "null"], + "items": { + "$ref": "#/$defs/SessionConfigOption" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "session/resume" + }, + "CloseSessionResponse": { + "description": "Response from closing a session.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "session/close" + }, + "SetSessionModeResponse": { + "description": "Response to `session/set_mode` method.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "session/set_mode" + }, + "SetSessionConfigOptionResponse": { + "description": "Response to `session/set_config_option` method.", + "type": "object", + "properties": { + "configOptions": { + "description": "The full set of configuration options and their current values.", + "type": "array", + "items": { + "$ref": "#/$defs/SessionConfigOption" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["configOptions"], + "x-side": "agent", + "x-method": "session/set_config_option" + }, + "PromptResponse": { + "description": "Response from processing a user prompt.\n\nSee protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)", + "type": "object", + "properties": { + "stopReason": { + "description": "Indicates why the agent stopped processing the turn.", + "allOf": [ + { + "$ref": "#/$defs/StopReason" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["stopReason"], + "x-side": "agent", + "x-method": "session/prompt" + }, + "StopReason": { + "description": "Reasons why an agent stops processing a prompt turn.\n\nSee protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)", + "oneOf": [ + { + "description": "The turn ended successfully.", + "type": "string", + "const": "end_turn" + }, + { + "description": "The turn ended because the agent reached the maximum number of tokens.", + "type": "string", + "const": "max_tokens" + }, + { + "description": "The turn ended because the agent reached the maximum number of allowed\nagent requests between user turns.", + "type": "string", + "const": "max_turn_requests" + }, + { + "description": "The turn ended because the agent refused to continue. The user prompt\nand everything that comes after it won't be included in the next\nprompt, so this should be reflected in the UI.", + "type": "string", + "const": "refusal" + }, + { + "description": "The turn was cancelled by the client via `session/cancel`.\n\nThis stop reason MUST be returned when the client sends a `session/cancel`\nnotification, even if the cancellation causes exceptions in underlying operations.\nAgents should catch these exceptions and return this semantically meaningful\nresponse to confirm successful cancellation.", + "type": "string", + "const": "cancelled" + } + ] + }, + "ExtResponse": { + "description": "Allows for sending an arbitrary response to an [`ExtRequest`] that is not part of the ACP spec.\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)" + }, + "Error": { + "description": "JSON-RPC error object.\n\nRepresents an error that occurred during method execution, following the\nJSON-RPC 2.0 error object specification with optional additional data.\n\nSee protocol docs: [JSON-RPC Error Object](https://www.jsonrpc.org/specification#error_object)", + "type": "object", + "properties": { + "code": { + "description": "A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification.", + "allOf": [ + { + "$ref": "#/$defs/ErrorCode" + } + ] + }, + "message": { + "description": "A string providing a short description of the error.\nThe message should be limited to a concise single sentence.", + "type": "string" + }, + "data": { + "description": "Optional primitive or structured value that contains additional information about the error.\nThis may include debugging information or context-specific details.", + "x-deserialize-default-on-error": true + } + }, + "required": ["code", "message"] + }, + "ErrorCode": { + "description": "Predefined error codes for common JSON-RPC and ACP-specific errors.\n\nThese codes follow the JSON-RPC 2.0 specification for standard errors\nand use the reserved range (-32000 to -32099) for protocol-specific errors.", + "anyOf": [ + { + "title": "Parse error", + "description": "**Parse error**: Invalid JSON was received by the server.\nAn error occurred on the server while parsing the JSON text.", + "type": "integer", + "format": "int32", + "const": -32700 + }, + { + "title": "Invalid request", + "description": "**Invalid request**: The JSON sent is not a valid Request object.", + "type": "integer", + "format": "int32", + "const": -32600 + }, + { + "title": "Method not found", + "description": "**Method not found**: The method does not exist or is not available.", + "type": "integer", + "format": "int32", + "const": -32601 + }, + { + "title": "Invalid params", + "description": "**Invalid params**: Invalid method parameter(s).", + "type": "integer", + "format": "int32", + "const": -32602 + }, + { + "title": "Internal error", + "description": "**Internal error**: Internal JSON-RPC error.\nReserved for implementation-defined server errors.", + "type": "integer", + "format": "int32", + "const": -32603 + }, + { + "title": "Request cancelled", + "description": "**Request cancelled**: Execution of the method was aborted either due to a cancellation request from the caller or\nbecause of resource constraints or shutdown.", + "type": "integer", + "format": "int32", + "const": -32800 + }, + { + "title": "Authentication required", + "description": "**Authentication required**: Authentication is required before this operation can be performed.", + "type": "integer", + "format": "int32", + "const": -32000 + }, + { + "title": "Resource not found", + "description": "**Resource not found**: A given resource, such as a file, was not found.", + "type": "integer", + "format": "int32", + "const": -32002 + }, + { + "title": "Other", + "description": "Other undefined error code.", + "type": "integer", + "format": "int32" + } + ] + }, + "AgentNotification": { + "description": "A JSON-RPC notification object.", + "type": "object", + "properties": { + "method": { + "description": "The notification method name.", + "type": "string" + }, + "params": { + "description": "Method-specific notification parameters.", + "anyOf": [ + { + "description": "All possible notifications that an agent can send to a client.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response.", + "anyOf": [ + { + "title": "SessionNotification", + "description": "Handles session update notifications from the agent.\n\nThis is a notification endpoint (no response expected) that receives\nreal-time updates about session progress, including message chunks,\ntool calls, and execution plans.\n\nNote: Clients SHOULD continue accepting tool call updates even after\nsending a `session/cancel` notification, as the agent may send final\nupdates before responding with the cancelled stop reason.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)", + "allOf": [ + { + "$ref": "#/$defs/SessionNotification" + } + ] + }, + { + "title": "ExtNotification", + "description": "Handles extension notifications from the agent.\n\nAllows the Agent to send an arbitrary notification that is not part of the ACP spec.\nExtension notifications provide a way to send one-way messages for custom functionality\nwhile maintaining protocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "allOf": [ + { + "$ref": "#/$defs/ExtNotification" + } + ] + } + ] + }, + { + "type": "null" + } + ] + } + }, + "required": ["method"], + "x-docs-ignore": true + }, + "SessionNotification": { + "description": "Notification containing a session update from the agent.\n\nUsed to stream real-time progress and results during prompt processing.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session this update pertains to.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "update": { + "description": "The actual update content.", + "allOf": [ + { + "$ref": "#/$defs/SessionUpdate" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "update"], + "x-side": "client", + "x-method": "session/update" + }, + "SessionUpdate": { + "description": "Different types of updates that can be sent during session processing.\n\nThese updates provide real-time feedback about the agent's progress.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)", + "oneOf": [ + { + "description": "A chunk of the user's message being streamed.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "user_message_chunk" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/ContentChunk" + } + ] + }, + { + "description": "A chunk of the agent's response being streamed.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "agent_message_chunk" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/ContentChunk" + } + ] + }, + { + "description": "A chunk of the agent's internal reasoning being streamed.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "agent_thought_chunk" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/ContentChunk" + } + ] + }, + { + "description": "Notification that a new tool call has been initiated.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "tool_call" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/ToolCall" + } + ] + }, + { + "description": "Update on the status or results of a tool call.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "tool_call_update" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/ToolCallUpdate" + } + ] + }, + { + "description": "The agent's execution plan for complex tasks.\nSee protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "plan" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/Plan" + } + ] + }, + { + "description": "Available commands are ready or have changed", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "available_commands_update" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/AvailableCommandsUpdate" + } + ] + }, + { + "description": "The current mode of the session has changed\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "current_mode_update" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/CurrentModeUpdate" + } + ] + }, + { + "description": "Session configuration options have been updated.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "config_option_update" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/ConfigOptionUpdate" + } + ] + }, + { + "description": "Session metadata has been updated (title, timestamps, custom metadata)", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "session_info_update" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/SessionInfoUpdate" + } + ] + }, + { + "description": "Context window and cost update for the session.", + "type": "object", + "properties": { + "sessionUpdate": { + "type": "string", + "const": "usage_update" + } + }, + "required": ["sessionUpdate"], + "allOf": [ + { + "$ref": "#/$defs/UsageUpdate" + } + ] + } + ], + "discriminator": { + "propertyName": "sessionUpdate" + } + }, + "MessageId": { + "description": "Unique identifier for a message within a session.", + "type": "string" + }, + "ContentChunk": { + "description": "A streamed item of content", + "type": "object", + "properties": { + "content": { + "description": "A single item of content", + "allOf": [ + { + "$ref": "#/$defs/ContentBlock" + } + ] + }, + "messageId": { + "description": "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started.", + "anyOf": [ + { + "$ref": "#/$defs/MessageId" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["content"] + }, + "ToolCall": { + "description": "Represents a tool call that the language model has requested.\n\nTool calls are actions that the agent executes on behalf of the language model,\nsuch as reading files, executing code, or fetching data from external sources.\n\nSee protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls)", + "type": "object", + "properties": { + "toolCallId": { + "description": "Unique identifier for this tool call within the session.", + "allOf": [ + { + "$ref": "#/$defs/ToolCallId" + } + ] + }, + "title": { + "description": "Human-readable title describing what the tool is doing.", + "type": "string" + }, + "kind": { + "description": "The category of tool being invoked.\nHelps clients choose appropriate icons and UI treatment.", + "x-deserialize-default-on-error": true, + "allOf": [ + { + "$ref": "#/$defs/ToolKind" + } + ] + }, + "status": { + "description": "Current execution status of the tool call.", + "x-deserialize-default-on-error": true, + "allOf": [ + { + "$ref": "#/$defs/ToolCallStatus" + } + ] + }, + "content": { + "description": "Content produced by the tool call.", + "type": "array", + "items": { + "$ref": "#/$defs/ToolCallContent" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "locations": { + "description": "File locations affected by this tool call.\nEnables \"follow-along\" features in clients.", + "type": "array", + "items": { + "$ref": "#/$defs/ToolCallLocation" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "rawInput": { + "description": "Raw input parameters sent to the tool.", + "x-deserialize-default-on-error": true + }, + "rawOutput": { + "description": "Raw output returned by the tool.", + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["toolCallId", "title"] + }, + "PlanEntry": { + "description": "A single entry in the execution plan.\n\nRepresents a task or goal that the assistant intends to accomplish\nas part of fulfilling the user's request.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)", + "type": "object", + "properties": { + "content": { + "description": "Human-readable description of what this task aims to accomplish.", + "type": "string" + }, + "priority": { + "description": "The relative importance of this task.\nUsed to indicate which tasks are most critical to the overall goal.", + "allOf": [ + { + "$ref": "#/$defs/PlanEntryPriority" + } + ] + }, + "status": { + "description": "Current execution status of this task.", + "allOf": [ + { + "$ref": "#/$defs/PlanEntryStatus" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["content", "priority", "status"] + }, + "PlanEntryPriority": { + "description": "Priority levels for plan entries.\n\nUsed to indicate the relative importance or urgency of different\ntasks in the execution plan.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)", + "oneOf": [ + { + "description": "High priority task - critical to the overall goal.", + "type": "string", + "const": "high" + }, + { + "description": "Medium priority task - important but not critical.", + "type": "string", + "const": "medium" + }, + { + "description": "Low priority task - nice to have but not essential.", + "type": "string", + "const": "low" + } + ] + }, + "PlanEntryStatus": { + "description": "Status of a plan entry in the execution flow.\n\nTracks the lifecycle of each task from planning through completion.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)", + "oneOf": [ + { + "description": "The task has not started yet.", + "type": "string", + "const": "pending" + }, + { + "description": "The task is currently being worked on.", + "type": "string", + "const": "in_progress" + }, + { + "description": "The task has been successfully completed.", + "type": "string", + "const": "completed" + } + ] + }, + "Plan": { + "description": "An execution plan for accomplishing complex tasks.\n\nPlans consist of multiple entries representing individual tasks or goals.\nAgents report plans to clients to provide visibility into their execution strategy.\nPlans can evolve during execution as the agent discovers new requirements or completes tasks.\n\nSee protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)", + "type": "object", + "properties": { + "entries": { + "description": "The list of tasks to be accomplished.\n\nWhen updating a plan, the agent must send a complete list of all entries\nwith their current status. The client replaces the entire plan with each update.", + "type": "array", + "items": { + "$ref": "#/$defs/PlanEntry" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["entries"] + }, + "AvailableCommand": { + "description": "Information about a command.", + "type": "object", + "properties": { + "name": { + "description": "Command name (e.g., `create_plan`, `research_codebase`).", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the command does.", + "type": "string" + }, + "input": { + "description": "Input for the command if required", + "anyOf": [ + { + "$ref": "#/$defs/AvailableCommandInput" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "description"] + }, + "AvailableCommandInput": { + "description": "The input specification for a command.", + "anyOf": [ + { + "title": "unstructured", + "description": "All text that was typed after the command name is provided as input.", + "allOf": [ + { + "$ref": "#/$defs/UnstructuredCommandInput" + } + ] + } + ] + }, + "UnstructuredCommandInput": { + "description": "All text that was typed after the command name is provided as input.", + "type": "object", + "properties": { + "hint": { + "description": "A hint to display when the input hasn't been provided yet", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["hint"] + }, + "AvailableCommandsUpdate": { + "description": "Available commands are ready or have changed", + "type": "object", + "properties": { + "availableCommands": { + "description": "Commands the agent can execute", + "type": "array", + "items": { + "$ref": "#/$defs/AvailableCommand" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["availableCommands"] + }, + "CurrentModeUpdate": { + "description": "The current mode of the session has changed\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "type": "object", + "properties": { + "currentModeId": { + "description": "The ID of the current mode", + "allOf": [ + { + "$ref": "#/$defs/SessionModeId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["currentModeId"] + }, + "ConfigOptionUpdate": { + "description": "Session configuration options have been updated.", + "type": "object", + "properties": { + "configOptions": { + "description": "The full set of configuration options and their current values.", + "type": "array", + "items": { + "$ref": "#/$defs/SessionConfigOption" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["configOptions"] + }, + "SessionInfoUpdate": { + "description": "Update to session metadata. All fields are optional to support partial updates.\n\nAgents send this notification to update session information like title or custom metadata.\nThis allows clients to display dynamic session names and track session state changes.", + "type": "object", + "properties": { + "title": { + "description": "Human-readable title for the session. Set to null to clear.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "updatedAt": { + "description": "ISO 8601 timestamp of last activity. Set to null to clear.", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "Cost": { + "description": "Cost information for a session.", + "type": "object", + "properties": { + "amount": { + "description": "Total cumulative cost for session.", + "type": "number", + "format": "double" + }, + "currency": { + "description": "ISO 4217 currency code (e.g., \"USD\", \"EUR\").", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["amount", "currency"] + }, + "UsageUpdate": { + "description": "Context window and cost update for a session.", + "type": "object", + "properties": { + "used": { + "description": "Tokens currently in context.", + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "size": { + "description": "Total context window size in tokens.", + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "cost": { + "description": "Cumulative session cost (optional).", + "anyOf": [ + { + "$ref": "#/$defs/Cost" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["used", "size"] + }, + "ExtNotification": { + "description": "Allows the Agent to send an arbitrary notification that is not part of the ACP spec.\nExtension notifications provide a way to send one-way messages for custom functionality\nwhile maintaining protocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)" + }, + "ClientRequest": { + "description": "A JSON-RPC request object.", + "type": "object", + "properties": { + "id": { + "description": "The request id used to correlate the matching response.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "method": { + "description": "The method name to invoke.", + "type": "string" + }, + "params": { + "description": "Method-specific request parameters.", + "anyOf": [ + { + "description": "All possible requests that a client can send to an agent.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly.\n\nThis enum encompasses all method calls from client to agent.", + "anyOf": [ + { + "title": "InitializeRequest", + "description": "Establishes the connection with a client and negotiates protocol capabilities.\n\nThis method is called once at the beginning of the connection to:\n- Negotiate the protocol version to use\n- Exchange capability information between client and agent\n- Determine available authentication methods\n\nThe agent should respond with its supported protocol version and capabilities.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)", + "allOf": [ + { + "$ref": "#/$defs/InitializeRequest" + } + ] + }, + { + "title": "AuthenticateRequest", + "description": "Authenticates the client using the specified authentication method.\n\nCalled when the agent requires authentication before allowing session creation.\nThe client provides the authentication method ID that was advertised during initialization.\n\nAfter successful authentication, the client can proceed to create sessions with\n`new_session` without receiving an `auth_required` error.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)", + "allOf": [ + { + "$ref": "#/$defs/AuthenticateRequest" + } + ] + }, + { + "title": "LogoutRequest", + "description": "Logs out of the current authenticated state.\n\nAfter a successful logout, all new sessions will require authentication.\nThere is no guarantee about the behavior of already running sessions.", + "allOf": [ + { + "$ref": "#/$defs/LogoutRequest" + } + ] + }, + { + "title": "NewSessionRequest", + "description": "Creates a new conversation session with the agent.\n\nSessions represent independent conversation contexts with their own history and state.\n\nThe agent should:\n- Create a new session context\n- Connect to any specified MCP servers\n- Return a unique session ID for future requests\n\nMay return an `auth_required` error if the agent requires authentication.\n\nSee protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)", + "allOf": [ + { + "$ref": "#/$defs/NewSessionRequest" + } + ] + }, + { + "title": "LoadSessionRequest", + "description": "Loads an existing session to resume a previous conversation.\n\nThis method is only available if the agent advertises the `loadSession` capability.\n\nThe agent should:\n- Restore the session context and conversation history\n- Connect to the specified MCP servers\n- Stream the entire conversation history back to the client via notifications\n\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)", + "allOf": [ + { + "$ref": "#/$defs/LoadSessionRequest" + } + ] + }, + { + "title": "ListSessionsRequest", + "description": "Lists existing sessions known to the agent.\n\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\n\nThe agent should return metadata about sessions with optional filtering and pagination support.", + "allOf": [ + { + "$ref": "#/$defs/ListSessionsRequest" + } + ] + }, + { + "title": "DeleteSessionRequest", + "description": "Deletes an existing session from `session/list`.\n\nThis method is only available if the agent advertises the `sessionCapabilities.delete` capability.", + "allOf": [ + { + "$ref": "#/$defs/DeleteSessionRequest" + } + ] + }, + { + "title": "ResumeSessionRequest", + "description": "Resumes an existing session without returning previous messages.\n\nThis method is only available if the agent advertises the `sessionCapabilities.resume` capability.\n\nThe agent should resume the session context, allowing the conversation to continue\nwithout replaying the message history (unlike `session/load`).", + "allOf": [ + { + "$ref": "#/$defs/ResumeSessionRequest" + } + ] + }, + { + "title": "CloseSessionRequest", + "description": "Closes an active session and frees up any resources associated with it.\n\nThis method is only available if the agent advertises the `sessionCapabilities.close` capability.\n\nThe agent must cancel any ongoing work (as if `session/cancel` was called)\nand then free up any resources associated with the session.", + "allOf": [ + { + "$ref": "#/$defs/CloseSessionRequest" + } + ] + }, + { + "title": "SetSessionModeRequest", + "description": "Sets the current mode for a session.\n\nAllows switching between different agent modes (e.g., \"ask\", \"architect\", \"code\")\nthat affect system prompts, tool availability, and permission behaviors.\n\nThe mode must be one of the modes advertised in `availableModes` during session\ncreation or loading. Agents may also change modes autonomously and notify the\nclient via `current_mode_update` notifications.\n\nThis method can be called at any time during a session, whether the Agent is\nidle or actively generating a response.\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)", + "allOf": [ + { + "$ref": "#/$defs/SetSessionModeRequest" + } + ] + }, + { + "title": "SetSessionConfigOptionRequest", + "description": "Sets the current value for a session configuration option.", + "allOf": [ + { + "$ref": "#/$defs/SetSessionConfigOptionRequest" + } + ] + }, + { + "title": "PromptRequest", + "description": "Processes a user prompt within a session.\n\nThis method handles the whole lifecycle of a prompt:\n- Receives user messages with optional context (files, images, etc.)\n- Processes the prompt using language models\n- Reports language model content and tool calls to the Clients\n- Requests permission to run tools\n- Executes any requested tool calls\n- Returns when the turn is complete with a stop reason\n\nSee protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)", + "allOf": [ + { + "$ref": "#/$defs/PromptRequest" + } + ] + }, + { + "title": "ExtMethodRequest", + "description": "Handles extension method requests from the client.\n\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "allOf": [ + { + "$ref": "#/$defs/ExtRequest" + } + ] + } + ] + }, + { + "type": "null" + } + ] + } + }, + "required": ["id", "method"], + "x-docs-ignore": true + }, + "InitializeRequest": { + "description": "Request parameters for the initialize method.\n\nSent by the client to establish connection and negotiate capabilities.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)", + "type": "object", + "properties": { + "protocolVersion": { + "description": "The latest protocol version supported by the client.", + "allOf": [ + { + "$ref": "#/$defs/ProtocolVersion" + } + ] + }, + "clientCapabilities": { + "description": "Capabilities supported by the client.", + "x-deserialize-default-on-error": true, + "default": { + "fs": { + "readTextFile": false, + "writeTextFile": false + }, + "terminal": false + }, + "allOf": [ + { + "$ref": "#/$defs/ClientCapabilities" + } + ] + }, + "clientInfo": { + "description": "Information about the Client name and version sent to the Agent.\n\nNote: in future versions of the protocol, this will be required.", + "anyOf": [ + { + "$ref": "#/$defs/Implementation" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["protocolVersion"], + "x-side": "agent", + "x-method": "initialize" + }, + "ClientCapabilities": { + "description": "Capabilities supported by the client.\n\nAdvertised during initialization to inform the agent about\navailable features and methods.\n\nSee protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)", + "type": "object", + "properties": { + "fs": { + "description": "File system capabilities supported by the client.\nDetermines which file operations the agent can request.", + "x-deserialize-default-on-error": true, + "default": { + "readTextFile": false, + "writeTextFile": false + }, + "allOf": [ + { + "$ref": "#/$defs/FileSystemCapabilities" + } + ] + }, + "terminal": { + "description": "Whether the Client support all `terminal/*` methods.", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "session": { + "description": "Session-related capabilities supported by the client.\n\nOptional. Omitted or `null` both mean the client does not advertise any\nsession-related extensions.", + "anyOf": [ + { + "$ref": "#/$defs/ClientSessionCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "FileSystemCapabilities": { + "description": "File system capabilities that a client may support.\n\nSee protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)", + "type": "object", + "properties": { + "readTextFile": { + "description": "Whether the Client supports `fs/read_text_file` requests.", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "writeTextFile": { + "description": "Whether the Client supports `fs/write_text_file` requests.", + "type": "boolean", + "default": false, + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "ClientSessionCapabilities": { + "description": "Session-related capabilities supported by the client.", + "type": "object", + "properties": { + "configOptions": { + "description": "Config option capabilities supported by the client.\n\nOmitted or `null` both mean the client does not advertise support for any\nconfig option extensions.", + "anyOf": [ + { + "$ref": "#/$defs/SessionConfigOptionsCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "SessionConfigOptionsCapabilities": { + "description": "Session configuration option capabilities supported by the client.", + "type": "object", + "properties": { + "boolean": { + "description": "Whether the client supports boolean session configuration options.\n\nOptional. Omitted or `null` both mean the client does not advertise support.\nSupplying `{}` means agents may include `type: \"boolean\"` entries in\n`configOptions`, and the client may send `session/set_config_option`\nrequests with `type: \"boolean\"` and a boolean `value`.", + "anyOf": [ + { + "$ref": "#/$defs/BooleanConfigOptionCapabilities" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "BooleanConfigOptionCapabilities": { + "description": "Capabilities for boolean session configuration options.\n\nSupplying `{}` means the client supports boolean session configuration options.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "AuthenticateRequest": { + "description": "Request parameters for the authenticate method.\n\nSpecifies which authentication method to use.", + "type": "object", + "properties": { + "methodId": { + "description": "The ID of the authentication method to use.\nMust be one of the methods advertised in the initialize response.", + "allOf": [ + { + "$ref": "#/$defs/AuthMethodId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["methodId"], + "x-side": "agent", + "x-method": "authenticate" + }, + "LogoutRequest": { + "description": "Request parameters for the logout method.\n\nTerminates the current authenticated session.", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "logout" + }, + "NewSessionRequest": { + "description": "Request parameters for creating a new session.\n\nSee protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)", + "type": "object", + "properties": { + "cwd": { + "description": "The working directory for this session. Must be an absolute path.", + "type": "string" + }, + "additionalDirectories": { + "description": "Additional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths. When omitted or empty, no\nadditional roots are activated for the new session.", + "type": "array", + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "mcpServers": { + "description": "List of MCP (Model Context Protocol) servers the agent should connect to.", + "type": "array", + "items": { + "$ref": "#/$defs/McpServer" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["cwd", "mcpServers"], + "x-side": "agent", + "x-method": "session/new" + }, + "McpServer": { + "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)", + "anyOf": [ + { + "description": "HTTP transport configuration\n\nOnly available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "http" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/McpServerHttp" + } + ] + }, + { + "description": "SSE transport configuration\n\nOnly available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.", + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "sse" + } + }, + "required": ["type"], + "allOf": [ + { + "$ref": "#/$defs/McpServerSse" + } + ] + }, + { + "title": "stdio", + "description": "Stdio transport configuration\n\nAll Agents MUST support this transport.", + "allOf": [ + { + "$ref": "#/$defs/McpServerStdio" + } + ] + } + ] + }, + "HttpHeader": { + "description": "An HTTP header to set when making requests to the MCP server.", + "type": "object", + "properties": { + "name": { + "description": "The name of the HTTP header.", + "type": "string" + }, + "value": { + "description": "The value to set for the HTTP header.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "value"] + }, + "McpServerHttp": { + "description": "HTTP transport configuration for MCP.", + "type": "object", + "properties": { + "name": { + "description": "Human-readable name identifying this MCP server.", + "type": "string" + }, + "url": { + "description": "URL to the MCP server.", + "type": "string" + }, + "headers": { + "description": "HTTP headers to set when making requests to the MCP server.", + "type": "array", + "items": { + "$ref": "#/$defs/HttpHeader" + } + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "url", "headers"] + }, + "McpServerSse": { + "description": "SSE transport configuration for MCP.", + "type": "object", + "properties": { + "name": { + "description": "Human-readable name identifying this MCP server.", + "type": "string" + }, + "url": { + "description": "URL to the MCP server.", + "type": "string" + }, + "headers": { + "description": "HTTP headers to set when making requests to the MCP server.", + "type": "array", + "items": { + "$ref": "#/$defs/HttpHeader" + } + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "url", "headers"] + }, + "McpServerStdio": { + "description": "Stdio transport configuration for MCP.", + "type": "object", + "properties": { + "name": { + "description": "Human-readable name identifying this MCP server.", + "type": "string" + }, + "command": { + "description": "Absolute path to the MCP server executable.", + "type": "string" + }, + "args": { + "description": "Command-line arguments to pass to the MCP server.", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "Environment variables to set when launching the MCP server.", + "type": "array", + "items": { + "$ref": "#/$defs/EnvVariable" + } + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["name", "command", "args", "env"] + }, + "LoadSessionRequest": { + "description": "Request parameters for loading an existing session.\n\nOnly available if the Agent supports the `loadSession` capability.\n\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)", + "type": "object", + "properties": { + "mcpServers": { + "description": "List of MCP servers to connect to for this session.", + "type": "array", + "items": { + "$ref": "#/$defs/McpServer" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "cwd": { + "description": "The working directory for this session. Must be an absolute path.", + "type": "string" + }, + "additionalDirectories": { + "description": "Additional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`.", + "type": "array", + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "sessionId": { + "description": "The ID of the session to load.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["mcpServers", "cwd", "sessionId"], + "x-side": "agent", + "x-method": "session/load" + }, + "ListSessionsRequest": { + "description": "Request parameters for listing existing sessions.\n\nOnly available if the Agent supports the `sessionCapabilities.list` capability.", + "type": "object", + "properties": { + "cwd": { + "description": "Filter sessions by working directory. Must be an absolute path.", + "type": ["string", "null"] + }, + "cursor": { + "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", + "type": ["string", "null"] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "agent", + "x-method": "session/list" + }, + "DeleteSessionRequest": { + "description": "Request parameters for deleting an existing session from `session/list`.\n\nOnly available if the Agent supports the `sessionCapabilities.delete` capability.", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to delete.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId"], + "x-side": "agent", + "x-method": "session/delete" + }, + "ResumeSessionRequest": { + "description": "Request parameters for resuming an existing session.\n\nResumes an existing session without returning previous messages (unlike `session/load`).\nThis is useful for agents that can resume sessions but don't implement full session loading.\n\nOnly available if the Agent supports the `sessionCapabilities.resume` capability.", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to resume.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "cwd": { + "description": "The working directory for this session. Must be an absolute path.", + "type": "string" + }, + "additionalDirectories": { + "description": "Additional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`.", + "type": "array", + "items": { + "type": "string" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "mcpServers": { + "description": "List of MCP servers to connect to for this session.", + "type": "array", + "items": { + "$ref": "#/$defs/McpServer" + }, + "x-deserialize-default-on-error": true, + "x-deserialize-skip-invalid-items": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "cwd"], + "x-side": "agent", + "x-method": "session/resume" + }, + "CloseSessionRequest": { + "description": "Request parameters for closing an active session.\n\nIf supported, the agent **must** cancel any ongoing work related to the session\n(treat it as if `session/cancel` was called) and then free up any resources\nassociated with the session.\n\nOnly available if the Agent supports the `sessionCapabilities.close` capability.", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to close.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId"], + "x-side": "agent", + "x-method": "session/close" + }, + "SetSessionModeRequest": { + "description": "Request parameters for setting a session mode.", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to set the mode for.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "modeId": { + "description": "The ID of the mode to set.", + "allOf": [ + { + "$ref": "#/$defs/SessionModeId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "modeId"], + "x-side": "agent", + "x-method": "session/set_mode" + }, + "SetSessionConfigOptionRequest": { + "description": "Request parameters for setting a session configuration option.", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to set the configuration option for.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "configId": { + "description": "The ID of the configuration option to set.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "configId"], + "anyOf": [ + { + "description": "A boolean value (`type: \"boolean\"`).", + "type": "object", + "properties": { + "value": { + "description": "The boolean value.", + "type": "boolean" + }, + "type": { + "type": "string", + "const": "boolean" + } + }, + "required": ["type", "value"] + }, + { + "title": "value_id", + "description": "A [`SessionConfigValueId`] string value.\n\nThis is the default when `type` is absent on the wire. Unknown `type`\nvalues with string payloads also gracefully deserialize into this\nvariant.", + "type": "object", + "properties": { + "value": { + "description": "The value ID.", + "allOf": [ + { + "$ref": "#/$defs/SessionConfigValueId" + } + ] + } + }, + "required": ["value"] + } + ], + "x-side": "agent", + "x-method": "session/set_config_option" + }, + "PromptRequest": { + "description": "Request parameters for sending a user prompt to the agent.\n\nContains the user's message and any additional context.\n\nSee protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to send this user message to", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "prompt": { + "description": "The blocks of content that compose the user's message.\n\nAs a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],\nwhile other variants are optionally enabled via [`PromptCapabilities`].\n\nThe Client MUST adapt its interface according to [`PromptCapabilities`].\n\nThe client MAY include referenced pieces of context as either\n[`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].\n\nWhen available, [`ContentBlock::Resource`] is preferred\nas it avoids extra round-trips and allows the message to include\npieces of context from sources the agent may not have access to.", + "type": "array", + "items": { + "$ref": "#/$defs/ContentBlock" + } + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId", "prompt"], + "x-side": "agent", + "x-method": "session/prompt" + }, + "ClientResponse": { + "description": "A JSON-RPC response object.", + "anyOf": [ + { + "title": "Result", + "description": "A successful JSON-RPC response.", + "type": "object", + "properties": { + "id": { + "description": "The id of the request this response answers.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "result": { + "description": "Method-specific response data.", + "anyOf": [ + { + "title": "WriteTextFileResponse", + "description": "Successful result returned for a `fs/write_text_file` request.", + "allOf": [ + { + "$ref": "#/$defs/WriteTextFileResponse" + } + ] + }, + { + "title": "ReadTextFileResponse", + "description": "Successful result returned for a `fs/read_text_file` request.", + "allOf": [ + { + "$ref": "#/$defs/ReadTextFileResponse" + } + ] + }, + { + "title": "RequestPermissionResponse", + "description": "Successful result returned for a `session/request_permission` request.", + "allOf": [ + { + "$ref": "#/$defs/RequestPermissionResponse" + } + ] + }, + { + "title": "CreateTerminalResponse", + "description": "Successful result returned for a `terminal/create` request.", + "allOf": [ + { + "$ref": "#/$defs/CreateTerminalResponse" + } + ] + }, + { + "title": "TerminalOutputResponse", + "description": "Successful result returned for a `terminal/output` request.", + "allOf": [ + { + "$ref": "#/$defs/TerminalOutputResponse" + } + ] + }, + { + "title": "ReleaseTerminalResponse", + "description": "Successful result returned for a `terminal/release` request.", + "allOf": [ + { + "$ref": "#/$defs/ReleaseTerminalResponse" + } + ] + }, + { + "title": "WaitForTerminalExitResponse", + "description": "Successful result returned for a `terminal/wait_for_exit` request.", + "allOf": [ + { + "$ref": "#/$defs/WaitForTerminalExitResponse" + } + ] + }, + { + "title": "KillTerminalResponse", + "description": "Successful result returned for a `terminal/kill` request.", + "allOf": [ + { + "$ref": "#/$defs/KillTerminalResponse" + } + ] + }, + { + "title": "ExtMethodResponse", + "description": "Successful result returned by an extension method outside the core ACP method set.", + "allOf": [ + { + "$ref": "#/$defs/ExtResponse" + } + ] + } + ] + } + }, + "required": ["id", "result"] + }, + { + "title": "Error", + "description": "A failed JSON-RPC response.", + "type": "object", + "properties": { + "id": { + "description": "The id of the request this response answers.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "error": { + "description": "Method-specific error data.", + "allOf": [ + { + "$ref": "#/$defs/Error" + } + ] + } + }, + "required": ["id", "error"] + } + ], + "x-docs-ignore": true + }, + "WriteTextFileResponse": { + "description": "Response to `fs/write_text_file`", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "client", + "x-method": "fs/write_text_file" + }, + "ReadTextFileResponse": { + "description": "Response containing the contents of a text file.", + "type": "object", + "properties": { + "content": { + "description": "Content payload returned by this response.", + "type": "string" + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["content"], + "x-side": "client", + "x-method": "fs/read_text_file" + }, + "RequestPermissionResponse": { + "description": "Response to a permission request.", + "type": "object", + "properties": { + "outcome": { + "description": "The user's decision on the permission request.", + "allOf": [ + { + "$ref": "#/$defs/RequestPermissionOutcome" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["outcome"], + "x-side": "client", + "x-method": "session/request_permission" + }, + "RequestPermissionOutcome": { + "description": "The outcome of a permission request.", + "oneOf": [ + { + "description": "The prompt turn was cancelled before the user responded.\n\nWhen a client sends a `session/cancel` notification to cancel an ongoing\nprompt turn, it MUST respond to all pending `session/request_permission`\nrequests with this `Cancelled` outcome.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)", + "type": "object", + "properties": { + "outcome": { + "type": "string", + "const": "cancelled" + } + }, + "required": ["outcome"] + }, + { + "description": "The user selected one of the provided options.", + "type": "object", + "properties": { + "outcome": { + "type": "string", + "const": "selected" + } + }, + "required": ["outcome"], + "allOf": [ + { + "$ref": "#/$defs/SelectedPermissionOutcome" + } + ] + } + ], + "discriminator": { + "propertyName": "outcome" + } + }, + "SelectedPermissionOutcome": { + "description": "The user selected one of the provided options.", + "type": "object", + "properties": { + "optionId": { + "description": "The ID of the option the user selected.", + "allOf": [ + { + "$ref": "#/$defs/PermissionOptionId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["optionId"] + }, + "CreateTerminalResponse": { + "description": "Response containing the ID of the created terminal.", + "type": "object", + "properties": { + "terminalId": { + "description": "The unique identifier for the created terminal.", + "allOf": [ + { + "$ref": "#/$defs/TerminalId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["terminalId"], + "x-side": "client", + "x-method": "terminal/create" + }, + "TerminalOutputResponse": { + "description": "Response containing the terminal output and exit status.", + "type": "object", + "properties": { + "output": { + "description": "The terminal output captured so far.", + "type": "string" + }, + "truncated": { + "description": "Whether the output was truncated due to byte limits.", + "type": "boolean" + }, + "exitStatus": { + "description": "Exit status if the command has completed.", + "anyOf": [ + { + "$ref": "#/$defs/TerminalExitStatus" + }, + { + "type": "null" + } + ], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["output", "truncated"], + "x-side": "client", + "x-method": "terminal/output" + }, + "TerminalExitStatus": { + "description": "Exit status of a terminal command.", + "type": "object", + "properties": { + "exitCode": { + "description": "The process exit code (may be null if terminated by signal).", + "type": ["integer", "null"], + "format": "uint32", + "minimum": 0, + "x-deserialize-default-on-error": true + }, + "signal": { + "description": "The signal that terminated the process (may be null if exited normally).", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + } + }, + "ReleaseTerminalResponse": { + "description": "Response to terminal/release method", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "client", + "x-method": "terminal/release" + }, + "WaitForTerminalExitResponse": { + "description": "Response containing the exit status of a terminal command.", + "type": "object", + "properties": { + "exitCode": { + "description": "The process exit code (may be null if terminated by signal).", + "type": ["integer", "null"], + "format": "uint32", + "minimum": 0, + "x-deserialize-default-on-error": true + }, + "signal": { + "description": "The signal that terminated the process (may be null if exited normally).", + "type": ["string", "null"], + "x-deserialize-default-on-error": true + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "client", + "x-method": "terminal/wait_for_exit" + }, + "KillTerminalResponse": { + "description": "Response to `terminal/kill` method", + "type": "object", + "properties": { + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "x-side": "client", + "x-method": "terminal/kill" + }, + "ClientNotification": { + "description": "A JSON-RPC notification object.", + "type": "object", + "properties": { + "method": { + "description": "The notification method name.", + "type": "string" + }, + "params": { + "description": "Method-specific notification parameters.", + "anyOf": [ + { + "description": "All possible notifications that a client can send to an agent.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response.", + "anyOf": [ + { + "title": "CancelNotification", + "description": "Cancels ongoing operations for a session.\n\nThis is a notification sent by the client to cancel an ongoing prompt turn.\n\nUpon receiving this notification, the Agent SHOULD:\n- Stop all language model requests as soon as possible\n- Abort all tool call invocations in progress\n- Send any pending `session/update` notifications\n- Respond to the original `session/prompt` request with `StopReason::Cancelled`\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)", + "allOf": [ + { + "$ref": "#/$defs/CancelNotification" + } + ] + }, + { + "title": "ExtNotification", + "description": "Handles extension notifications from the client.\n\nExtension notifications provide a way to send one-way messages for custom functionality\nwhile maintaining protocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "allOf": [ + { + "$ref": "#/$defs/ExtNotification" + } + ] + } + ] + }, + { + "type": "null" + } + ] + } + }, + "required": ["method"], + "x-docs-ignore": true + }, + "CancelNotification": { + "description": "Notification to cancel ongoing operations for a session.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)", + "type": "object", + "properties": { + "sessionId": { + "description": "The ID of the session to cancel operations for.", + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["sessionId"], + "x-side": "agent", + "x-method": "session/cancel" + }, + "CancelRequestNotification": { + "description": "Notification to cancel an ongoing request.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)", + "type": "object", + "properties": { + "requestId": { + "description": "The ID of the request to cancel.", + "allOf": [ + { + "$ref": "#/$defs/RequestId" + } + ] + }, + "_meta": { + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"], + "x-deserialize-default-on-error": true, + "additionalProperties": true + } + }, + "required": ["requestId"], + "x-side": "protocol", + "x-method": "$/cancel_request" + } + } +} diff --git a/crates/openab-gateway/src/adapters/acp_schema.rs b/crates/openab-gateway/src/adapters/acp_schema.rs new file mode 100644 index 000000000..873c45a90 --- /dev/null +++ b/crates/openab-gateway/src/adapters/acp_schema.rs @@ -0,0 +1,23203 @@ +//! ACP v1 wire types — GENERATED, do not edit by hand. +//! +//! Source schema: `agentclientprotocol/agent-client-protocol` +//! `schema/v1/schema.json` @ `eb88e992521c350fc87b51207baa4ea4877ce0dd` (ACP Schema v1.19.0), +//! vendored at `crates/openab-gateway/schemas/acp-v1.schema.json`. +//! Generator: `cargo-typify 0.7.0` — plain serde, **no** `schemars` / `serde_with` runtime dep. +//! Regenerate: +//! `cargo typify --output crates/openab-gateway/src/adapters/acp_schema.rs \` +//! `crates/openab-gateway/schemas/acp-v1.schema.json` +//! +//! The full v1 surface is generated (it is one closed dependency graph — `SessionUpdate` +//! alone reaches most defs, so a hand-trimmed "chat subset" would not be meaningfully +//! smaller and would diverge from the schema). The base wires only the chat subset +//! (Initialize / NewSession / Resume / Prompt / StopReason / ContentBlock / +//! SessionNotification); the rest (tool_call, fs/*, terminal/*, permission) is inert +//! until the bidirectional / MCP-over-ACP roadmap consumes it. + +#![allow(clippy::redundant_closure_call)] +#![allow(clippy::needless_lifetimes)] +#![allow(clippy::match_single_binding)] +#![allow(clippy::clone_on_copy)] + +#[doc = r" Error types."] +pub mod error { + #[doc = r" Error from a `TryFrom` or `FromStr` implementation."] + pub struct ConversionError(::std::borrow::Cow<'static, str>); + impl ::std::error::Error for ConversionError {} + impl ::std::fmt::Display for ConversionError { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Display::fmt(&self.0, f) + } + } + impl ::std::fmt::Debug for ConversionError { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> { + ::std::fmt::Debug::fmt(&self.0, f) + } + } + impl From<&'static str> for ConversionError { + fn from(value: &'static str) -> Self { + Self(value.into()) + } + } + impl From for ConversionError { + fn from(value: String) -> Self { + Self(value.into()) + } + } +} +#[doc = "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"title\": \"Agent\","] +#[doc = " \"description\": \"A message (request, response, or notification) with `\\\"jsonrpc\\\": \\\"2.0\\\"` specified as\\n[required by JSON-RPC 2.0 Specification][1].\\n\\n[1]: https://www.jsonrpc.org/specification#compatibility\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Request\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Response\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Notification\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum Agent { + Variant0 { + #[doc = "The request id used to correlate the matching response."] + id: RequestId, + jsonrpc: AgentVariant0Jsonrpc, + #[doc = "The method name to invoke."] + method: ::std::string::String, + #[doc = "Method-specific request parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + params: ::std::option::Option, + }, + Variant1(AgentVariant1), + Variant2 { + jsonrpc: AgentVariant2Jsonrpc, + #[doc = "The notification method name."] + method: ::std::string::String, + #[doc = "Method-specific notification parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + params: ::std::option::Option, + }, +} +impl ::std::convert::From for Agent { + fn from(value: AgentVariant1) -> Self { + Self::Variant1(value) + } +} +#[doc = "Authentication-related capabilities supported by the agent."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Authentication-related capabilities supported by the agent.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"logout\": {"] +#[doc = " \"description\": \"Whether the agent supports the logout method.\\n\\nOptional. Omitted or `null` both mean the agent does not advertise support.\\nSupplying `{}` means the agent supports the logout method.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LogoutCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentAuthCapabilities { + #[doc = "Whether the agent supports the logout method.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports the logout method."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub logout: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for AgentAuthCapabilities { + fn default() -> Self { + Self { + logout: Default::default(), + meta: Default::default(), + } + } +} +impl AgentAuthCapabilities { + pub fn builder() -> builder::AgentAuthCapabilities { + Default::default() + } +} +#[doc = "Capabilities supported by the agent.\n\nAdvertised during initialization to inform the client about\navailable features and content types.\n\nSee protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities supported by the agent.\\n\\nAdvertised during initialization to inform the client about\\navailable features and content types.\\n\\nSee protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"auth\": {"] +#[doc = " \"description\": \"Authentication-related capabilities supported by the agent.\","] +#[doc = " \"default\": {},"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentAuthCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"loadSession\": {"] +#[doc = " \"description\": \"Whether the agent supports `session/load`.\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"mcpCapabilities\": {"] +#[doc = " \"description\": \"MCP capabilities supported by the agent.\","] +#[doc = " \"default\": {"] +#[doc = " \"http\": false,"] +#[doc = " \"sse\": false"] +#[doc = " },"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/McpCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"promptCapabilities\": {"] +#[doc = " \"description\": \"Prompt capabilities supported by the agent.\","] +#[doc = " \"default\": {"] +#[doc = " \"audio\": false,"] +#[doc = " \"embeddedContext\": false,"] +#[doc = " \"image\": false"] +#[doc = " },"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PromptCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionCapabilities\": {"] +#[doc = " \"description\": \"Session lifecycle and prompt capabilities advertised by the agent.\","] +#[doc = " \"default\": {},"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentCapabilities { + #[doc = "Authentication-related capabilities supported by the agent."] + #[serde(default = "defaults::agent_capabilities_auth")] + pub auth: AgentAuthCapabilities, + #[doc = "Whether the agent supports `session/load`."] + #[serde(rename = "loadSession", default)] + pub load_session: bool, + #[doc = "MCP capabilities supported by the agent."] + #[serde( + rename = "mcpCapabilities", + default = "defaults::agent_capabilities_mcp_capabilities" + )] + pub mcp_capabilities: McpCapabilities, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Prompt capabilities supported by the agent."] + #[serde( + rename = "promptCapabilities", + default = "defaults::agent_capabilities_prompt_capabilities" + )] + pub prompt_capabilities: PromptCapabilities, + #[doc = "Session lifecycle and prompt capabilities advertised by the agent."] + #[serde( + rename = "sessionCapabilities", + default = "defaults::agent_capabilities_session_capabilities" + )] + pub session_capabilities: SessionCapabilities, +} +impl ::std::default::Default for AgentCapabilities { + fn default() -> Self { + Self { + auth: defaults::agent_capabilities_auth(), + load_session: Default::default(), + mcp_capabilities: defaults::agent_capabilities_mcp_capabilities(), + meta: Default::default(), + prompt_capabilities: defaults::agent_capabilities_prompt_capabilities(), + session_capabilities: defaults::agent_capabilities_session_capabilities(), + } + } +} +impl AgentCapabilities { + pub fn builder() -> builder::AgentCapabilities { + Default::default() + } +} +#[doc = "`AgentClientProtocol`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"title\": \"Agent Client Protocol\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Agent\","] +#[doc = " \"description\": \"A message (request, response, or notification) with `\\\"jsonrpc\\\": \\\"2.0\\\"` specified as\\n[required by JSON-RPC 2.0 Specification][1].\\n\\n[1]: https://www.jsonrpc.org/specification#compatibility\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Request\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Response\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Notification\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Client\","] +#[doc = " \"description\": \"A message (request, response, or notification) with `\\\"jsonrpc\\\": \\\"2.0\\\"` specified as\\n[required by JSON-RPC 2.0 Specification][1].\\n\\n[1]: https://www.jsonrpc.org/specification#compatibility\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Request\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Response\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Notification\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ProtocolLevel\","] +#[doc = " \"description\": \"A message (request, response, or notification) with `\\\"jsonrpc\\\": \\\"2.0\\\"` specified as\\n[required by JSON-RPC 2.0 Specification][1].\\n\\n[1]: https://www.jsonrpc.org/specification#compatibility\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\","] +#[doc = " \"method\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"method\": {"] +#[doc = " \"description\": \"The notification method name.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"params\": {"] +#[doc = " \"description\": \"Method-specific notification parameters.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"General protocol-level notifications that all sides are expected to\\nimplement.\\n\\nNotifications whose methods start with '$/' are messages which\\nare protocol implementation dependent and might not be implementable in all\\nclients or agents. For example if the implementation uses a single threaded\\nsynchronous programming language then there is little it can do to react to\\na `$/cancel_request` notification. If an agent or client receives\\nnotifications starting with '$/' it is free to ignore the notification.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"CancelRequestNotification\","] +#[doc = " \"description\": \"Cancels an ongoing request.\\n\\nThis is a notification sent by the side that sent a request to cancel that request.\\n\\nUpon receiving this notification, the receiver:\\n\\n1. MAY cancel the corresponding request activity and all nested activities\\n2. MAY send any pending notifications.\\n3. MUST send one of these responses for the original request:\\n - Valid response with appropriate data (partial results or cancellation marker)\\n - Error response with code `-32800` (Cancelled)\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CancelRequestNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentClientProtocol { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, +} +impl ::std::default::Default for AgentClientProtocol { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + } + } +} +impl AgentClientProtocol { + pub fn builder() -> builder::AgentClientProtocol { + Default::default() + } +} +#[doc = "A JSON-RPC notification object."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A JSON-RPC notification object.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"method\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"method\": {"] +#[doc = " \"description\": \"The notification method name.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"params\": {"] +#[doc = " \"description\": \"Method-specific notification parameters.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"All possible notifications that an agent can send to a client.\\n\\nThis enum is used internally for routing RPC notifications. You typically won't need\\nto use this directly.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"SessionNotification\","] +#[doc = " \"description\": \"Handles session update notifications from the agent.\\n\\nThis is a notification endpoint (no response expected) that receives\\nreal-time updates about session progress, including message chunks,\\ntool calls, and execution plans.\\n\\nNote: Clients SHOULD continue accepting tool call updates even after\\nsending a `session/cancel` notification, as the agent may send final\\nupdates before responding with the cancelled stop reason.\\n\\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtNotification\","] +#[doc = " \"description\": \"Handles extension notifications from the agent.\\n\\nAllows the Agent to send an arbitrary notification that is not part of the ACP spec.\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentNotification { + #[doc = "The notification method name."] + pub method: ::std::string::String, + #[doc = "Method-specific notification parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub params: ::std::option::Option, +} +impl AgentNotification { + pub fn builder() -> builder::AgentNotification { + Default::default() + } +} +#[doc = "All possible notifications that an agent can send to a client.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible notifications that an agent can send to a client.\\n\\nThis enum is used internally for routing RPC notifications. You typically won't need\\nto use this directly.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"SessionNotification\","] +#[doc = " \"description\": \"Handles session update notifications from the agent.\\n\\nThis is a notification endpoint (no response expected) that receives\\nreal-time updates about session progress, including message chunks,\\ntool calls, and execution plans.\\n\\nNote: Clients SHOULD continue accepting tool call updates even after\\nsending a `session/cancel` notification, as the agent may send final\\nupdates before responding with the cancelled stop reason.\\n\\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtNotification\","] +#[doc = " \"description\": \"Handles extension notifications from the agent.\\n\\nAllows the Agent to send an arbitrary notification that is not part of the ACP spec.\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentNotificationParams { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, +} +impl ::std::default::Default for AgentNotificationParams { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + } + } +} +impl AgentNotificationParams { + pub fn builder() -> builder::AgentNotificationParams { + Default::default() + } +} +#[doc = "A JSON-RPC request object."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A JSON-RPC request object.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"method\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"The request id used to correlate the matching response.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"method\": {"] +#[doc = " \"description\": \"The method name to invoke.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"params\": {"] +#[doc = " \"description\": \"Method-specific request parameters.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"All possible requests that an agent can send to a client.\\n\\nThis enum is used internally for routing RPC requests. You typically won't need\\nto use this directly.\\n\\nThis enum encompasses all method calls from agent to client.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"WriteTextFileRequest\","] +#[doc = " \"description\": \"Writes content to a text file in the client's file system.\\n\\nOnly available if the client advertises the `fs.writeTextFile` capability.\\nAllows the agent to create or modify files within the client's environment.\\n\\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WriteTextFileRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReadTextFileRequest\","] +#[doc = " \"description\": \"Reads content from a text file in the client's file system.\\n\\nOnly available if the client advertises the `fs.readTextFile` capability.\\nAllows the agent to access file contents within the client's environment.\\n\\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReadTextFileRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"RequestPermissionRequest\","] +#[doc = " \"description\": \"Requests permission from the user for a tool call operation.\\n\\nCalled by the agent when it needs user authorization before executing\\na potentially sensitive operation. The client should present the options\\nto the user and return their decision.\\n\\nIf the client cancels the prompt turn via `session/cancel`, it MUST\\nrespond to this request with `RequestPermissionOutcome::Cancelled`.\\n\\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestPermissionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CreateTerminalRequest\","] +#[doc = " \"description\": \"Executes a command in a new terminal\\n\\nOnly available if the `terminal` Client capability is set to `true`.\\n\\nReturns a `TerminalId` that can be used with other terminal methods\\nto get the current output, wait for exit, and kill the command.\\n\\nThe `TerminalId` can also be used to embed the terminal in a tool call\\nby using the `ToolCallContent::Terminal` variant.\\n\\nThe Agent is responsible for releasing the terminal by using the `terminal/release`\\nmethod.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CreateTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"TerminalOutputRequest\","] +#[doc = " \"description\": \"Gets the terminal output and exit status\\n\\nReturns the current content in the terminal without waiting for the command to exit.\\nIf the command has already exited, the exit status is included.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalOutputRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReleaseTerminalRequest\","] +#[doc = " \"description\": \"Releases a terminal\\n\\nThe command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`\\nto wait for the command to exit before releasing the terminal.\\n\\nAfter release, the `TerminalId` can no longer be used with other `terminal/*` methods,\\nbut tool calls that already contain it, continue to display its output.\\n\\nThe `terminal/kill` method can be used to terminate the command without releasing\\nthe terminal, allowing the Agent to call `terminal/output` and other methods.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReleaseTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"WaitForTerminalExitRequest\","] +#[doc = " \"description\": \"Waits for the terminal command to exit and return its exit status\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WaitForTerminalExitRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"KillTerminalRequest\","] +#[doc = " \"description\": \"Kills the terminal command without releasing the terminal\\n\\nWhile `terminal/release` will also kill the command, this method will keep\\nthe `TerminalId` valid so it can be used with other methods.\\n\\nThis method can be helpful when implementing command timeouts which terminate\\nthe command as soon as elapsed, and then get the final output so it can be sent\\nto the model.\\n\\nNote: Call `terminal/release` when `TerminalId` is no longer needed.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/KillTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodRequest\","] +#[doc = " \"description\": \"Handles extension method requests from the agent.\\n\\nAllows the Agent to send an arbitrary request that is not part of the ACP spec.\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentRequest { + #[doc = "The request id used to correlate the matching response."] + pub id: RequestId, + #[doc = "The method name to invoke."] + pub method: ::std::string::String, + #[doc = "Method-specific request parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub params: ::std::option::Option, +} +impl AgentRequest { + pub fn builder() -> builder::AgentRequest { + Default::default() + } +} +#[doc = "All possible requests that an agent can send to a client.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly.\n\nThis enum encompasses all method calls from agent to client."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible requests that an agent can send to a client.\\n\\nThis enum is used internally for routing RPC requests. You typically won't need\\nto use this directly.\\n\\nThis enum encompasses all method calls from agent to client.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"WriteTextFileRequest\","] +#[doc = " \"description\": \"Writes content to a text file in the client's file system.\\n\\nOnly available if the client advertises the `fs.writeTextFile` capability.\\nAllows the agent to create or modify files within the client's environment.\\n\\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WriteTextFileRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReadTextFileRequest\","] +#[doc = " \"description\": \"Reads content from a text file in the client's file system.\\n\\nOnly available if the client advertises the `fs.readTextFile` capability.\\nAllows the agent to access file contents within the client's environment.\\n\\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReadTextFileRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"RequestPermissionRequest\","] +#[doc = " \"description\": \"Requests permission from the user for a tool call operation.\\n\\nCalled by the agent when it needs user authorization before executing\\na potentially sensitive operation. The client should present the options\\nto the user and return their decision.\\n\\nIf the client cancels the prompt turn via `session/cancel`, it MUST\\nrespond to this request with `RequestPermissionOutcome::Cancelled`.\\n\\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestPermissionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CreateTerminalRequest\","] +#[doc = " \"description\": \"Executes a command in a new terminal\\n\\nOnly available if the `terminal` Client capability is set to `true`.\\n\\nReturns a `TerminalId` that can be used with other terminal methods\\nto get the current output, wait for exit, and kill the command.\\n\\nThe `TerminalId` can also be used to embed the terminal in a tool call\\nby using the `ToolCallContent::Terminal` variant.\\n\\nThe Agent is responsible for releasing the terminal by using the `terminal/release`\\nmethod.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CreateTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"TerminalOutputRequest\","] +#[doc = " \"description\": \"Gets the terminal output and exit status\\n\\nReturns the current content in the terminal without waiting for the command to exit.\\nIf the command has already exited, the exit status is included.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalOutputRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReleaseTerminalRequest\","] +#[doc = " \"description\": \"Releases a terminal\\n\\nThe command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`\\nto wait for the command to exit before releasing the terminal.\\n\\nAfter release, the `TerminalId` can no longer be used with other `terminal/*` methods,\\nbut tool calls that already contain it, continue to display its output.\\n\\nThe `terminal/kill` method can be used to terminate the command without releasing\\nthe terminal, allowing the Agent to call `terminal/output` and other methods.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReleaseTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"WaitForTerminalExitRequest\","] +#[doc = " \"description\": \"Waits for the terminal command to exit and return its exit status\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WaitForTerminalExitRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"KillTerminalRequest\","] +#[doc = " \"description\": \"Kills the terminal command without releasing the terminal\\n\\nWhile `terminal/release` will also kill the command, this method will keep\\nthe `TerminalId` valid so it can be used with other methods.\\n\\nThis method can be helpful when implementing command timeouts which terminate\\nthe command as soon as elapsed, and then get the final output so it can be sent\\nto the model.\\n\\nNote: Call `terminal/release` when `TerminalId` is no longer needed.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/KillTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodRequest\","] +#[doc = " \"description\": \"Handles extension method requests from the agent.\\n\\nAllows the Agent to send an arbitrary request that is not part of the ACP spec.\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentRequestParams { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_5: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_6: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_7: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_8: ::std::option::Option, +} +impl ::std::default::Default for AgentRequestParams { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + subtype_5: Default::default(), + subtype_6: Default::default(), + subtype_7: Default::default(), + subtype_8: Default::default(), + } + } +} +impl AgentRequestParams { + pub fn builder() -> builder::AgentRequestParams { + Default::default() + } +} +#[doc = "A JSON-RPC response object."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A JSON-RPC response object.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Result\","] +#[doc = " \"description\": \"A successful JSON-RPC response.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"result\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"The id of the request this response answers.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"result\": {"] +#[doc = " \"description\": \"Method-specific response data.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"InitializeResponse\","] +#[doc = " \"description\": \"Successful result returned for a `initialize` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/InitializeResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"AuthenticateResponse\","] +#[doc = " \"description\": \"Successful result returned for a `authenticate` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthenticateResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LogoutResponse\","] +#[doc = " \"description\": \"Successful result returned for a `logout` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LogoutResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"NewSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/new` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/NewSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LoadSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/load` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LoadSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ListSessionsResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/list` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ListSessionsResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"DeleteSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/delete` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/DeleteSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ResumeSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/resume` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ResumeSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CloseSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/close` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CloseSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionModeResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/set_mode` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionModeResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionConfigOptionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/set_config_option` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionConfigOptionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"PromptResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/prompt` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PromptResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodResponse\","] +#[doc = " \"description\": \"Successful result returned by an extension method outside the core ACP method set.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Error\","] +#[doc = " \"description\": \"A failed JSON-RPC response.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"error\","] +#[doc = " \"id\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"error\": {"] +#[doc = " \"description\": \"Method-specific error data.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Error\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"The id of the request this response answers.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum AgentResponse { + Result { + #[doc = "The id of the request this response answers."] + id: RequestId, + #[doc = "Method-specific response data."] + result: ResultResult, + }, + Error { + #[doc = "Method-specific error data."] + error: Error, + #[doc = "The id of the request this response answers."] + id: RequestId, + }, +} +#[doc = "`AgentVariant0Jsonrpc`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum AgentVariant0Jsonrpc { + #[serde(rename = "2.0")] + X20, +} +impl ::std::fmt::Display for AgentVariant0Jsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } +} +impl ::std::str::FromStr for AgentVariant0Jsonrpc { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for AgentVariant0Jsonrpc { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for AgentVariant0Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for AgentVariant0Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "All possible requests that an agent can send to a client.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly.\n\nThis enum encompasses all method calls from agent to client."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible requests that an agent can send to a client.\\n\\nThis enum is used internally for routing RPC requests. You typically won't need\\nto use this directly.\\n\\nThis enum encompasses all method calls from agent to client.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"WriteTextFileRequest\","] +#[doc = " \"description\": \"Writes content to a text file in the client's file system.\\n\\nOnly available if the client advertises the `fs.writeTextFile` capability.\\nAllows the agent to create or modify files within the client's environment.\\n\\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WriteTextFileRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReadTextFileRequest\","] +#[doc = " \"description\": \"Reads content from a text file in the client's file system.\\n\\nOnly available if the client advertises the `fs.readTextFile` capability.\\nAllows the agent to access file contents within the client's environment.\\n\\nSee protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReadTextFileRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"RequestPermissionRequest\","] +#[doc = " \"description\": \"Requests permission from the user for a tool call operation.\\n\\nCalled by the agent when it needs user authorization before executing\\na potentially sensitive operation. The client should present the options\\nto the user and return their decision.\\n\\nIf the client cancels the prompt turn via `session/cancel`, it MUST\\nrespond to this request with `RequestPermissionOutcome::Cancelled`.\\n\\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestPermissionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CreateTerminalRequest\","] +#[doc = " \"description\": \"Executes a command in a new terminal\\n\\nOnly available if the `terminal` Client capability is set to `true`.\\n\\nReturns a `TerminalId` that can be used with other terminal methods\\nto get the current output, wait for exit, and kill the command.\\n\\nThe `TerminalId` can also be used to embed the terminal in a tool call\\nby using the `ToolCallContent::Terminal` variant.\\n\\nThe Agent is responsible for releasing the terminal by using the `terminal/release`\\nmethod.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CreateTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"TerminalOutputRequest\","] +#[doc = " \"description\": \"Gets the terminal output and exit status\\n\\nReturns the current content in the terminal without waiting for the command to exit.\\nIf the command has already exited, the exit status is included.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalOutputRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReleaseTerminalRequest\","] +#[doc = " \"description\": \"Releases a terminal\\n\\nThe command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`\\nto wait for the command to exit before releasing the terminal.\\n\\nAfter release, the `TerminalId` can no longer be used with other `terminal/*` methods,\\nbut tool calls that already contain it, continue to display its output.\\n\\nThe `terminal/kill` method can be used to terminate the command without releasing\\nthe terminal, allowing the Agent to call `terminal/output` and other methods.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReleaseTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"WaitForTerminalExitRequest\","] +#[doc = " \"description\": \"Waits for the terminal command to exit and return its exit status\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WaitForTerminalExitRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"KillTerminalRequest\","] +#[doc = " \"description\": \"Kills the terminal command without releasing the terminal\\n\\nWhile `terminal/release` will also kill the command, this method will keep\\nthe `TerminalId` valid so it can be used with other methods.\\n\\nThis method can be helpful when implementing command timeouts which terminate\\nthe command as soon as elapsed, and then get the final output so it can be sent\\nto the model.\\n\\nNote: Call `terminal/release` when `TerminalId` is no longer needed.\\n\\nSee protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/KillTerminalRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodRequest\","] +#[doc = " \"description\": \"Handles extension method requests from the agent.\\n\\nAllows the Agent to send an arbitrary request that is not part of the ACP spec.\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentVariant0Params { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_5: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_6: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_7: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_8: ::std::option::Option, +} +impl ::std::default::Default for AgentVariant0Params { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + subtype_5: Default::default(), + subtype_6: Default::default(), + subtype_7: Default::default(), + subtype_8: Default::default(), + } + } +} +impl AgentVariant0Params { + pub fn builder() -> builder::AgentVariant0Params { + Default::default() + } +} +#[doc = "`AgentVariant1`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Response\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"not\": {"] +#[doc = " \"title\": \"Request\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"not\": {"] +#[doc = " \"title\": \"Notification\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(deny_unknown_fields)] +pub enum AgentVariant1 {} +#[doc = "`AgentVariant2Jsonrpc`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum AgentVariant2Jsonrpc { + #[serde(rename = "2.0")] + X20, +} +impl ::std::fmt::Display for AgentVariant2Jsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } +} +impl ::std::str::FromStr for AgentVariant2Jsonrpc { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for AgentVariant2Jsonrpc { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for AgentVariant2Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for AgentVariant2Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "All possible notifications that an agent can send to a client.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible notifications that an agent can send to a client.\\n\\nThis enum is used internally for routing RPC notifications. You typically won't need\\nto use this directly.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"SessionNotification\","] +#[doc = " \"description\": \"Handles session update notifications from the agent.\\n\\nThis is a notification endpoint (no response expected) that receives\\nreal-time updates about session progress, including message chunks,\\ntool calls, and execution plans.\\n\\nNote: Clients SHOULD continue accepting tool call updates even after\\nsending a `session/cancel` notification, as the agent may send final\\nupdates before responding with the cancelled stop reason.\\n\\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtNotification\","] +#[doc = " \"description\": \"Handles extension notifications from the agent.\\n\\nAllows the Agent to send an arbitrary notification that is not part of the ACP spec.\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AgentVariant2Params { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, +} +impl ::std::default::Default for AgentVariant2Params { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + } + } +} +impl AgentVariant2Params { + pub fn builder() -> builder::AgentVariant2Params { + Default::default() + } +} +#[doc = "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Optional annotations for the client. The client can use annotations to inform how objects are used or displayed\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"audience\": {"] +#[doc = " \"description\": \"Intended recipients for this content, such as the user or assistant.\","] +#[doc = " \"type\": ["] +#[doc = " \"array\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/Role\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"lastModified\": {"] +#[doc = " \"description\": \"Timestamp indicating when the underlying resource was last modified.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"priority\": {"] +#[doc = " \"description\": \"Relative importance of this content when clients choose what to surface.\","] +#[doc = " \"type\": ["] +#[doc = " \"number\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"double\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Annotations { + #[doc = "Intended recipients for this content, such as the user or assistant."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub audience: ::std::option::Option<::std::vec::Vec>, + #[doc = "Timestamp indicating when the underlying resource was last modified."] + #[serde( + rename = "lastModified", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub last_modified: ::std::option::Option<::std::string::String>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Relative importance of this content when clients choose what to surface."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub priority: ::std::option::Option, +} +impl ::std::default::Default for Annotations { + fn default() -> Self { + Self { + audience: Default::default(), + last_modified: Default::default(), + meta: Default::default(), + priority: Default::default(), + } + } +} +impl Annotations { + pub fn builder() -> builder::Annotations { + Default::default() + } +} +#[doc = "Audio provided to or from an LLM."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Audio provided to or from an LLM.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"data\","] +#[doc = " \"mimeType\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"annotations\": {"] +#[doc = " \"description\": \"Optional annotations that help clients decide how to display or route this content.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Annotations\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"data\": {"] +#[doc = " \"description\": \"Base64-encoded media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"mimeType\": {"] +#[doc = " \"description\": \"MIME type describing the encoded media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AudioContent { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub annotations: ::std::option::Option, + #[doc = "Base64-encoded media payload."] + pub data: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde(rename = "mimeType")] + pub mime_type: ::std::string::String, +} +impl AudioContent { + pub fn builder() -> builder::AudioContent { + Default::default() + } +} +#[doc = "Describes an available authentication method.\n\nThe `type` field acts as the discriminator in the serialized JSON form.\nWhen no `type` is present, the method is treated as `agent`."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Describes an available authentication method.\\n\\nThe `type` field acts as the discriminator in the serialized JSON form.\\nWhen no `type` is present, the method is treated as `agent`.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"agent\","] +#[doc = " \"description\": \"Agent handles authentication itself.\\n\\nThis is the default when no `type` is specified.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthMethodAgent\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct AuthMethod(pub AuthMethodAgent); +impl ::std::ops::Deref for AuthMethod { + type Target = AuthMethodAgent; + fn deref(&self) -> &AuthMethodAgent { + &self.0 + } +} +impl ::std::convert::From for AuthMethodAgent { + fn from(value: AuthMethod) -> Self { + value.0 + } +} +impl ::std::convert::From for AuthMethod { + fn from(value: AuthMethodAgent) -> Self { + Self(value) + } +} +#[doc = "Agent handles authentication itself.\n\nThis is the default authentication method type."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Agent handles authentication itself.\\n\\nThis is the default authentication method type.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"name\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"description\": {"] +#[doc = " \"description\": \"Optional description providing more details about this authentication method.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"Unique identifier for this authentication method.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthMethodId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable name of the authentication method.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AuthMethodAgent { + #[doc = "Optional description providing more details about this authentication method."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub description: ::std::option::Option<::std::string::String>, + #[doc = "Unique identifier for this authentication method."] + pub id: AuthMethodId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name of the authentication method."] + pub name: ::std::string::String, +} +impl AuthMethodAgent { + pub fn builder() -> builder::AuthMethodAgent { + Default::default() + } +} +#[doc = "Typed identifier used for auth method values on the wire."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Typed identifier used for auth method values on the wire.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct AuthMethodId(pub ::std::string::String); +impl ::std::ops::Deref for AuthMethodId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: AuthMethodId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for AuthMethodId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for AuthMethodId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for AuthMethodId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Request parameters for the authenticate method.\n\nSpecifies which authentication method to use."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for the authenticate method.\\n\\nSpecifies which authentication method to use.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"methodId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"methodId\": {"] +#[doc = " \"description\": \"The ID of the authentication method to use.\\nMust be one of the methods advertised in the initialize response.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthMethodId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"authenticate\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AuthenticateRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the authentication method to use.\nMust be one of the methods advertised in the initialize response."] + #[serde(rename = "methodId")] + pub method_id: AuthMethodId, +} +impl AuthenticateRequest { + pub fn builder() -> builder::AuthenticateRequest { + Default::default() + } +} +#[doc = "Response to the `authenticate` method."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to the `authenticate` method.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"authenticate\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AuthenticateResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for AuthenticateResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl AuthenticateResponse { + pub fn builder() -> builder::AuthenticateResponse { + Default::default() + } +} +#[doc = "Information about a command."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Information about a command.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"description\","] +#[doc = " \"name\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"description\": {"] +#[doc = " \"description\": \"Human-readable description of what the command does.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"input\": {"] +#[doc = " \"description\": \"Input for the command if required\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AvailableCommandInput\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Command name (e.g., `create_plan`, `research_codebase`).\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AvailableCommand { + #[doc = "Human-readable description of what the command does."] + pub description: ::std::string::String, + #[doc = "Input for the command if required"] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub input: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Command name (e.g., `create_plan`, `research_codebase`)."] + pub name: ::std::string::String, +} +impl AvailableCommand { + pub fn builder() -> builder::AvailableCommand { + Default::default() + } +} +#[doc = "The input specification for a command."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The input specification for a command.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"unstructured\","] +#[doc = " \"description\": \"All text that was typed after the command name is provided as input.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/UnstructuredCommandInput\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct AvailableCommandInput(pub UnstructuredCommandInput); +impl ::std::ops::Deref for AvailableCommandInput { + type Target = UnstructuredCommandInput; + fn deref(&self) -> &UnstructuredCommandInput { + &self.0 + } +} +impl ::std::convert::From for UnstructuredCommandInput { + fn from(value: AvailableCommandInput) -> Self { + value.0 + } +} +impl ::std::convert::From for AvailableCommandInput { + fn from(value: UnstructuredCommandInput) -> Self { + Self(value) + } +} +#[doc = "Available commands are ready or have changed"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Available commands are ready or have changed\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"availableCommands\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"availableCommands\": {"] +#[doc = " \"description\": \"Commands the agent can execute\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/AvailableCommand\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct AvailableCommandsUpdate { + #[doc = "Commands the agent can execute"] + #[serde(rename = "availableCommands")] + pub available_commands: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl AvailableCommandsUpdate { + pub fn builder() -> builder::AvailableCommandsUpdate { + Default::default() + } +} +#[doc = "Binary resource contents."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Binary resource contents.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"blob\","] +#[doc = " \"uri\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"blob\": {"] +#[doc = " \"description\": \"Base64-encoded bytes for a binary resource payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"mimeType\": {"] +#[doc = " \"description\": \"MIME type describing the encoded media payload.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"uri\": {"] +#[doc = " \"description\": \"URI associated with this resource or media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct BlobResourceContents { + #[doc = "Base64-encoded bytes for a binary resource payload."] + pub blob: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde( + rename = "mimeType", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub mime_type: ::std::option::Option<::std::string::String>, + #[doc = "URI associated with this resource or media payload."] + pub uri: ::std::string::String, +} +impl BlobResourceContents { + pub fn builder() -> builder::BlobResourceContents { + Default::default() + } +} +#[doc = "Capabilities for boolean session configuration options.\n\nSupplying `{}` means the client supports boolean session configuration options."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities for boolean session configuration options.\\n\\nSupplying `{}` means the client supports boolean session configuration options.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct BooleanConfigOptionCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for BooleanConfigOptionCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl BooleanConfigOptionCapabilities { + pub fn builder() -> builder::BooleanConfigOptionCapabilities { + Default::default() + } +} +#[doc = "Notification to cancel ongoing operations for a session.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Notification to cancel ongoing operations for a session.\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to cancel operations for.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/cancel\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CancelNotification { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to cancel operations for."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl CancelNotification { + pub fn builder() -> builder::CancelNotification { + Default::default() + } +} +#[doc = "Notification to cancel an ongoing request.\n\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Notification to cancel an ongoing request.\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"requestId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"requestId\": {"] +#[doc = " \"description\": \"The ID of the request to cancel.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"$/cancel_request\","] +#[doc = " \"x-side\": \"protocol\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CancelRequestNotification { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the request to cancel."] + #[serde(rename = "requestId")] + pub request_id: RequestId, +} +impl CancelRequestNotification { + pub fn builder() -> builder::CancelRequestNotification { + Default::default() + } +} +#[doc = "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"title\": \"Client\","] +#[doc = " \"description\": \"A message (request, response, or notification) with `\\\"jsonrpc\\\": \\\"2.0\\\"` specified as\\n[required by JSON-RPC 2.0 Specification][1].\\n\\n[1]: https://www.jsonrpc.org/specification#compatibility\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Request\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Response\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Notification\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum Client { + Variant0 { + #[doc = "The request id used to correlate the matching response."] + id: RequestId, + jsonrpc: ClientVariant0Jsonrpc, + #[doc = "The method name to invoke."] + method: ::std::string::String, + #[doc = "Method-specific request parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + params: ::std::option::Option, + }, + Variant1(ClientVariant1), + Variant2 { + jsonrpc: ClientVariant2Jsonrpc, + #[doc = "The notification method name."] + method: ::std::string::String, + #[doc = "Method-specific notification parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + params: ::std::option::Option, + }, +} +impl ::std::convert::From for Client { + fn from(value: ClientVariant1) -> Self { + Self::Variant1(value) + } +} +#[doc = "Capabilities supported by the client.\n\nAdvertised during initialization to inform the agent about\navailable features and methods.\n\nSee protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities supported by the client.\\n\\nAdvertised during initialization to inform the agent about\\navailable features and methods.\\n\\nSee protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"fs\": {"] +#[doc = " \"description\": \"File system capabilities supported by the client.\\nDetermines which file operations the agent can request.\","] +#[doc = " \"default\": {"] +#[doc = " \"readTextFile\": false,"] +#[doc = " \"writeTextFile\": false"] +#[doc = " },"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/FileSystemCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"session\": {"] +#[doc = " \"description\": \"Session-related capabilities supported by the client.\\n\\nOptional. Omitted or `null` both mean the client does not advertise any\\nsession-related extensions.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientSessionCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"terminal\": {"] +#[doc = " \"description\": \"Whether the Client support all `terminal/*` methods.\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientCapabilities { + #[doc = "File system capabilities supported by the client.\nDetermines which file operations the agent can request."] + #[serde(default = "defaults::client_capabilities_fs")] + pub fs: FileSystemCapabilities, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Session-related capabilities supported by the client.\n\nOptional. Omitted or `null` both mean the client does not advertise any\nsession-related extensions."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub session: ::std::option::Option, + #[doc = "Whether the Client support all `terminal/*` methods."] + #[serde(default)] + pub terminal: bool, +} +impl ::std::default::Default for ClientCapabilities { + fn default() -> Self { + Self { + fs: defaults::client_capabilities_fs(), + meta: Default::default(), + session: Default::default(), + terminal: Default::default(), + } + } +} +impl ClientCapabilities { + pub fn builder() -> builder::ClientCapabilities { + Default::default() + } +} +#[doc = "A JSON-RPC notification object."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A JSON-RPC notification object.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"method\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"method\": {"] +#[doc = " \"description\": \"The notification method name.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"params\": {"] +#[doc = " \"description\": \"Method-specific notification parameters.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"All possible notifications that a client can send to an agent.\\n\\nThis enum is used internally for routing RPC notifications. You typically won't need\\nto use this directly.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"CancelNotification\","] +#[doc = " \"description\": \"Cancels ongoing operations for a session.\\n\\nThis is a notification sent by the client to cancel an ongoing prompt turn.\\n\\nUpon receiving this notification, the Agent SHOULD:\\n- Stop all language model requests as soon as possible\\n- Abort all tool call invocations in progress\\n- Send any pending `session/update` notifications\\n- Respond to the original `session/prompt` request with `StopReason::Cancelled`\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CancelNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtNotification\","] +#[doc = " \"description\": \"Handles extension notifications from the client.\\n\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientNotification { + #[doc = "The notification method name."] + pub method: ::std::string::String, + #[doc = "Method-specific notification parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub params: ::std::option::Option, +} +impl ClientNotification { + pub fn builder() -> builder::ClientNotification { + Default::default() + } +} +#[doc = "All possible notifications that a client can send to an agent.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible notifications that a client can send to an agent.\\n\\nThis enum is used internally for routing RPC notifications. You typically won't need\\nto use this directly.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"CancelNotification\","] +#[doc = " \"description\": \"Cancels ongoing operations for a session.\\n\\nThis is a notification sent by the client to cancel an ongoing prompt turn.\\n\\nUpon receiving this notification, the Agent SHOULD:\\n- Stop all language model requests as soon as possible\\n- Abort all tool call invocations in progress\\n- Send any pending `session/update` notifications\\n- Respond to the original `session/prompt` request with `StopReason::Cancelled`\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CancelNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtNotification\","] +#[doc = " \"description\": \"Handles extension notifications from the client.\\n\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientNotificationParams { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, +} +impl ::std::default::Default for ClientNotificationParams { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + } + } +} +impl ClientNotificationParams { + pub fn builder() -> builder::ClientNotificationParams { + Default::default() + } +} +#[doc = "A JSON-RPC request object."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A JSON-RPC request object.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"method\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"The request id used to correlate the matching response.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"method\": {"] +#[doc = " \"description\": \"The method name to invoke.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"params\": {"] +#[doc = " \"description\": \"Method-specific request parameters.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"All possible requests that a client can send to an agent.\\n\\nThis enum is used internally for routing RPC requests. You typically won't need\\nto use this directly.\\n\\nThis enum encompasses all method calls from client to agent.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"InitializeRequest\","] +#[doc = " \"description\": \"Establishes the connection with a client and negotiates protocol capabilities.\\n\\nThis method is called once at the beginning of the connection to:\\n- Negotiate the protocol version to use\\n- Exchange capability information between client and agent\\n- Determine available authentication methods\\n\\nThe agent should respond with its supported protocol version and capabilities.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/InitializeRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"AuthenticateRequest\","] +#[doc = " \"description\": \"Authenticates the client using the specified authentication method.\\n\\nCalled when the agent requires authentication before allowing session creation.\\nThe client provides the authentication method ID that was advertised during initialization.\\n\\nAfter successful authentication, the client can proceed to create sessions with\\n`new_session` without receiving an `auth_required` error.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthenticateRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LogoutRequest\","] +#[doc = " \"description\": \"Logs out of the current authenticated state.\\n\\nAfter a successful logout, all new sessions will require authentication.\\nThere is no guarantee about the behavior of already running sessions.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LogoutRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"NewSessionRequest\","] +#[doc = " \"description\": \"Creates a new conversation session with the agent.\\n\\nSessions represent independent conversation contexts with their own history and state.\\n\\nThe agent should:\\n- Create a new session context\\n- Connect to any specified MCP servers\\n- Return a unique session ID for future requests\\n\\nMay return an `auth_required` error if the agent requires authentication.\\n\\nSee protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/NewSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LoadSessionRequest\","] +#[doc = " \"description\": \"Loads an existing session to resume a previous conversation.\\n\\nThis method is only available if the agent advertises the `loadSession` capability.\\n\\nThe agent should:\\n- Restore the session context and conversation history\\n- Connect to the specified MCP servers\\n- Stream the entire conversation history back to the client via notifications\\n\\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LoadSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ListSessionsRequest\","] +#[doc = " \"description\": \"Lists existing sessions known to the agent.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\\n\\nThe agent should return metadata about sessions with optional filtering and pagination support.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ListSessionsRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"DeleteSessionRequest\","] +#[doc = " \"description\": \"Deletes an existing session from `session/list`.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.delete` capability.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/DeleteSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ResumeSessionRequest\","] +#[doc = " \"description\": \"Resumes an existing session without returning previous messages.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.resume` capability.\\n\\nThe agent should resume the session context, allowing the conversation to continue\\nwithout replaying the message history (unlike `session/load`).\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ResumeSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CloseSessionRequest\","] +#[doc = " \"description\": \"Closes an active session and frees up any resources associated with it.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.close` capability.\\n\\nThe agent must cancel any ongoing work (as if `session/cancel` was called)\\nand then free up any resources associated with the session.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CloseSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionModeRequest\","] +#[doc = " \"description\": \"Sets the current mode for a session.\\n\\nAllows switching between different agent modes (e.g., \\\"ask\\\", \\\"architect\\\", \\\"code\\\")\\nthat affect system prompts, tool availability, and permission behaviors.\\n\\nThe mode must be one of the modes advertised in `availableModes` during session\\ncreation or loading. Agents may also change modes autonomously and notify the\\nclient via `current_mode_update` notifications.\\n\\nThis method can be called at any time during a session, whether the Agent is\\nidle or actively generating a response.\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionModeRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionConfigOptionRequest\","] +#[doc = " \"description\": \"Sets the current value for a session configuration option.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionConfigOptionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"PromptRequest\","] +#[doc = " \"description\": \"Processes a user prompt within a session.\\n\\nThis method handles the whole lifecycle of a prompt:\\n- Receives user messages with optional context (files, images, etc.)\\n- Processes the prompt using language models\\n- Reports language model content and tool calls to the Clients\\n- Requests permission to run tools\\n- Executes any requested tool calls\\n- Returns when the turn is complete with a stop reason\\n\\nSee protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PromptRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodRequest\","] +#[doc = " \"description\": \"Handles extension method requests from the client.\\n\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientRequest { + #[doc = "The request id used to correlate the matching response."] + pub id: RequestId, + #[doc = "The method name to invoke."] + pub method: ::std::string::String, + #[doc = "Method-specific request parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub params: ::std::option::Option, +} +impl ClientRequest { + pub fn builder() -> builder::ClientRequest { + Default::default() + } +} +#[doc = "All possible requests that a client can send to an agent.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly.\n\nThis enum encompasses all method calls from client to agent."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible requests that a client can send to an agent.\\n\\nThis enum is used internally for routing RPC requests. You typically won't need\\nto use this directly.\\n\\nThis enum encompasses all method calls from client to agent.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"InitializeRequest\","] +#[doc = " \"description\": \"Establishes the connection with a client and negotiates protocol capabilities.\\n\\nThis method is called once at the beginning of the connection to:\\n- Negotiate the protocol version to use\\n- Exchange capability information between client and agent\\n- Determine available authentication methods\\n\\nThe agent should respond with its supported protocol version and capabilities.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/InitializeRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"AuthenticateRequest\","] +#[doc = " \"description\": \"Authenticates the client using the specified authentication method.\\n\\nCalled when the agent requires authentication before allowing session creation.\\nThe client provides the authentication method ID that was advertised during initialization.\\n\\nAfter successful authentication, the client can proceed to create sessions with\\n`new_session` without receiving an `auth_required` error.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthenticateRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LogoutRequest\","] +#[doc = " \"description\": \"Logs out of the current authenticated state.\\n\\nAfter a successful logout, all new sessions will require authentication.\\nThere is no guarantee about the behavior of already running sessions.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LogoutRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"NewSessionRequest\","] +#[doc = " \"description\": \"Creates a new conversation session with the agent.\\n\\nSessions represent independent conversation contexts with their own history and state.\\n\\nThe agent should:\\n- Create a new session context\\n- Connect to any specified MCP servers\\n- Return a unique session ID for future requests\\n\\nMay return an `auth_required` error if the agent requires authentication.\\n\\nSee protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/NewSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LoadSessionRequest\","] +#[doc = " \"description\": \"Loads an existing session to resume a previous conversation.\\n\\nThis method is only available if the agent advertises the `loadSession` capability.\\n\\nThe agent should:\\n- Restore the session context and conversation history\\n- Connect to the specified MCP servers\\n- Stream the entire conversation history back to the client via notifications\\n\\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LoadSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ListSessionsRequest\","] +#[doc = " \"description\": \"Lists existing sessions known to the agent.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\\n\\nThe agent should return metadata about sessions with optional filtering and pagination support.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ListSessionsRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"DeleteSessionRequest\","] +#[doc = " \"description\": \"Deletes an existing session from `session/list`.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.delete` capability.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/DeleteSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ResumeSessionRequest\","] +#[doc = " \"description\": \"Resumes an existing session without returning previous messages.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.resume` capability.\\n\\nThe agent should resume the session context, allowing the conversation to continue\\nwithout replaying the message history (unlike `session/load`).\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ResumeSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CloseSessionRequest\","] +#[doc = " \"description\": \"Closes an active session and frees up any resources associated with it.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.close` capability.\\n\\nThe agent must cancel any ongoing work (as if `session/cancel` was called)\\nand then free up any resources associated with the session.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CloseSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionModeRequest\","] +#[doc = " \"description\": \"Sets the current mode for a session.\\n\\nAllows switching between different agent modes (e.g., \\\"ask\\\", \\\"architect\\\", \\\"code\\\")\\nthat affect system prompts, tool availability, and permission behaviors.\\n\\nThe mode must be one of the modes advertised in `availableModes` during session\\ncreation or loading. Agents may also change modes autonomously and notify the\\nclient via `current_mode_update` notifications.\\n\\nThis method can be called at any time during a session, whether the Agent is\\nidle or actively generating a response.\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionModeRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionConfigOptionRequest\","] +#[doc = " \"description\": \"Sets the current value for a session configuration option.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionConfigOptionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"PromptRequest\","] +#[doc = " \"description\": \"Processes a user prompt within a session.\\n\\nThis method handles the whole lifecycle of a prompt:\\n- Receives user messages with optional context (files, images, etc.)\\n- Processes the prompt using language models\\n- Reports language model content and tool calls to the Clients\\n- Requests permission to run tools\\n- Executes any requested tool calls\\n- Returns when the turn is complete with a stop reason\\n\\nSee protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PromptRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodRequest\","] +#[doc = " \"description\": \"Handles extension method requests from the client.\\n\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientRequestParams { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_5: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_6: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_7: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_8: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_9: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_10: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_11: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_12: ::std::option::Option, +} +impl ::std::default::Default for ClientRequestParams { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + subtype_5: Default::default(), + subtype_6: Default::default(), + subtype_7: Default::default(), + subtype_8: Default::default(), + subtype_9: Default::default(), + subtype_10: Default::default(), + subtype_11: Default::default(), + subtype_12: Default::default(), + } + } +} +impl ClientRequestParams { + pub fn builder() -> builder::ClientRequestParams { + Default::default() + } +} +#[doc = "A JSON-RPC response object."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A JSON-RPC response object.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Result\","] +#[doc = " \"description\": \"A successful JSON-RPC response.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"result\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"The id of the request this response answers.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"result\": {"] +#[doc = " \"description\": \"Method-specific response data.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"WriteTextFileResponse\","] +#[doc = " \"description\": \"Successful result returned for a `fs/write_text_file` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WriteTextFileResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReadTextFileResponse\","] +#[doc = " \"description\": \"Successful result returned for a `fs/read_text_file` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReadTextFileResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"RequestPermissionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/request_permission` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestPermissionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CreateTerminalResponse\","] +#[doc = " \"description\": \"Successful result returned for a `terminal/create` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CreateTerminalResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"TerminalOutputResponse\","] +#[doc = " \"description\": \"Successful result returned for a `terminal/output` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalOutputResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ReleaseTerminalResponse\","] +#[doc = " \"description\": \"Successful result returned for a `terminal/release` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ReleaseTerminalResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"WaitForTerminalExitResponse\","] +#[doc = " \"description\": \"Successful result returned for a `terminal/wait_for_exit` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/WaitForTerminalExitResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"KillTerminalResponse\","] +#[doc = " \"description\": \"Successful result returned for a `terminal/kill` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/KillTerminalResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodResponse\","] +#[doc = " \"description\": \"Successful result returned by an extension method outside the core ACP method set.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Error\","] +#[doc = " \"description\": \"A failed JSON-RPC response.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"error\","] +#[doc = " \"id\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"error\": {"] +#[doc = " \"description\": \"Method-specific error data.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Error\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"The id of the request this response answers.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum ClientResponse { + Result { + #[doc = "The id of the request this response answers."] + id: RequestId, + #[doc = "Method-specific response data."] + result: ResultResult, + }, + Error { + #[doc = "Method-specific error data."] + error: Error, + #[doc = "The id of the request this response answers."] + id: RequestId, + }, +} +#[doc = "Session-related capabilities supported by the client."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Session-related capabilities supported by the client.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configOptions\": {"] +#[doc = " \"description\": \"Config option capabilities supported by the client.\\n\\nOmitted or `null` both mean the client does not advertise support for any\\nconfig option extensions.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOptionsCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientSessionCapabilities { + #[doc = "Config option capabilities supported by the client.\n\nOmitted or `null` both mean the client does not advertise support for any\nconfig option extensions."] + #[serde( + rename = "configOptions", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub config_options: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for ClientSessionCapabilities { + fn default() -> Self { + Self { + config_options: Default::default(), + meta: Default::default(), + } + } +} +impl ClientSessionCapabilities { + pub fn builder() -> builder::ClientSessionCapabilities { + Default::default() + } +} +#[doc = "`ClientVariant0Jsonrpc`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum ClientVariant0Jsonrpc { + #[serde(rename = "2.0")] + X20, +} +impl ::std::fmt::Display for ClientVariant0Jsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } +} +impl ::std::str::FromStr for ClientVariant0Jsonrpc { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for ClientVariant0Jsonrpc { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for ClientVariant0Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for ClientVariant0Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "All possible requests that a client can send to an agent.\n\nThis enum is used internally for routing RPC requests. You typically won't need\nto use this directly.\n\nThis enum encompasses all method calls from client to agent."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible requests that a client can send to an agent.\\n\\nThis enum is used internally for routing RPC requests. You typically won't need\\nto use this directly.\\n\\nThis enum encompasses all method calls from client to agent.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"InitializeRequest\","] +#[doc = " \"description\": \"Establishes the connection with a client and negotiates protocol capabilities.\\n\\nThis method is called once at the beginning of the connection to:\\n- Negotiate the protocol version to use\\n- Exchange capability information between client and agent\\n- Determine available authentication methods\\n\\nThe agent should respond with its supported protocol version and capabilities.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/InitializeRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"AuthenticateRequest\","] +#[doc = " \"description\": \"Authenticates the client using the specified authentication method.\\n\\nCalled when the agent requires authentication before allowing session creation.\\nThe client provides the authentication method ID that was advertised during initialization.\\n\\nAfter successful authentication, the client can proceed to create sessions with\\n`new_session` without receiving an `auth_required` error.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthenticateRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LogoutRequest\","] +#[doc = " \"description\": \"Logs out of the current authenticated state.\\n\\nAfter a successful logout, all new sessions will require authentication.\\nThere is no guarantee about the behavior of already running sessions.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LogoutRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"NewSessionRequest\","] +#[doc = " \"description\": \"Creates a new conversation session with the agent.\\n\\nSessions represent independent conversation contexts with their own history and state.\\n\\nThe agent should:\\n- Create a new session context\\n- Connect to any specified MCP servers\\n- Return a unique session ID for future requests\\n\\nMay return an `auth_required` error if the agent requires authentication.\\n\\nSee protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/NewSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LoadSessionRequest\","] +#[doc = " \"description\": \"Loads an existing session to resume a previous conversation.\\n\\nThis method is only available if the agent advertises the `loadSession` capability.\\n\\nThe agent should:\\n- Restore the session context and conversation history\\n- Connect to the specified MCP servers\\n- Stream the entire conversation history back to the client via notifications\\n\\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LoadSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ListSessionsRequest\","] +#[doc = " \"description\": \"Lists existing sessions known to the agent.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\\n\\nThe agent should return metadata about sessions with optional filtering and pagination support.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ListSessionsRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"DeleteSessionRequest\","] +#[doc = " \"description\": \"Deletes an existing session from `session/list`.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.delete` capability.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/DeleteSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ResumeSessionRequest\","] +#[doc = " \"description\": \"Resumes an existing session without returning previous messages.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.resume` capability.\\n\\nThe agent should resume the session context, allowing the conversation to continue\\nwithout replaying the message history (unlike `session/load`).\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ResumeSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CloseSessionRequest\","] +#[doc = " \"description\": \"Closes an active session and frees up any resources associated with it.\\n\\nThis method is only available if the agent advertises the `sessionCapabilities.close` capability.\\n\\nThe agent must cancel any ongoing work (as if `session/cancel` was called)\\nand then free up any resources associated with the session.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CloseSessionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionModeRequest\","] +#[doc = " \"description\": \"Sets the current mode for a session.\\n\\nAllows switching between different agent modes (e.g., \\\"ask\\\", \\\"architect\\\", \\\"code\\\")\\nthat affect system prompts, tool availability, and permission behaviors.\\n\\nThe mode must be one of the modes advertised in `availableModes` during session\\ncreation or loading. Agents may also change modes autonomously and notify the\\nclient via `current_mode_update` notifications.\\n\\nThis method can be called at any time during a session, whether the Agent is\\nidle or actively generating a response.\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionModeRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionConfigOptionRequest\","] +#[doc = " \"description\": \"Sets the current value for a session configuration option.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionConfigOptionRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"PromptRequest\","] +#[doc = " \"description\": \"Processes a user prompt within a session.\\n\\nThis method handles the whole lifecycle of a prompt:\\n- Receives user messages with optional context (files, images, etc.)\\n- Processes the prompt using language models\\n- Reports language model content and tool calls to the Clients\\n- Requests permission to run tools\\n- Executes any requested tool calls\\n- Returns when the turn is complete with a stop reason\\n\\nSee protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PromptRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodRequest\","] +#[doc = " \"description\": \"Handles extension method requests from the client.\\n\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientVariant0Params { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_5: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_6: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_7: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_8: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_9: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_10: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_11: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_12: ::std::option::Option, +} +impl ::std::default::Default for ClientVariant0Params { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + subtype_5: Default::default(), + subtype_6: Default::default(), + subtype_7: Default::default(), + subtype_8: Default::default(), + subtype_9: Default::default(), + subtype_10: Default::default(), + subtype_11: Default::default(), + subtype_12: Default::default(), + } + } +} +impl ClientVariant0Params { + pub fn builder() -> builder::ClientVariant0Params { + Default::default() + } +} +#[doc = "`ClientVariant1`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Response\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"not\": {"] +#[doc = " \"title\": \"Request\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientRequest\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"not\": {"] +#[doc = " \"title\": \"Notification\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(deny_unknown_fields)] +pub enum ClientVariant1 {} +#[doc = "`ClientVariant2Jsonrpc`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum ClientVariant2Jsonrpc { + #[serde(rename = "2.0")] + X20, +} +impl ::std::fmt::Display for ClientVariant2Jsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } +} +impl ::std::str::FromStr for ClientVariant2Jsonrpc { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for ClientVariant2Jsonrpc { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for ClientVariant2Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for ClientVariant2Jsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "All possible notifications that a client can send to an agent.\n\nThis enum is used internally for routing RPC notifications. You typically won't need\nto use this directly.\n\nNotifications do not expect a response."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All possible notifications that a client can send to an agent.\\n\\nThis enum is used internally for routing RPC notifications. You typically won't need\\nto use this directly.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"CancelNotification\","] +#[doc = " \"description\": \"Cancels ongoing operations for a session.\\n\\nThis is a notification sent by the client to cancel an ongoing prompt turn.\\n\\nUpon receiving this notification, the Agent SHOULD:\\n- Stop all language model requests as soon as possible\\n- Abort all tool call invocations in progress\\n- Send any pending `session/update` notifications\\n- Respond to the original `session/prompt` request with `StopReason::Cancelled`\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CancelNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtNotification\","] +#[doc = " \"description\": \"Handles extension notifications from the client.\\n\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ClientVariant2Params { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, +} +impl ::std::default::Default for ClientVariant2Params { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + } + } +} +impl ClientVariant2Params { + pub fn builder() -> builder::ClientVariant2Params { + Default::default() + } +} +#[doc = "Request parameters for closing an active session.\n\nIf supported, the agent **must** cancel any ongoing work related to the session\n(treat it as if `session/cancel` was called) and then free up any resources\nassociated with the session.\n\nOnly available if the Agent supports the `sessionCapabilities.close` capability."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for closing an active session.\\n\\nIf supported, the agent **must** cancel any ongoing work related to the session\\n(treat it as if `session/cancel` was called) and then free up any resources\\nassociated with the session.\\n\\nOnly available if the Agent supports the `sessionCapabilities.close` capability.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to close.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/close\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CloseSessionRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to close."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl CloseSessionRequest { + pub fn builder() -> builder::CloseSessionRequest { + Default::default() + } +} +#[doc = "Response from closing a session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from closing a session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/close\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CloseSessionResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for CloseSessionResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl CloseSessionResponse { + pub fn builder() -> builder::CloseSessionResponse { + Default::default() + } +} +#[doc = "Session configuration options have been updated."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Session configuration options have been updated.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"configOptions\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configOptions\": {"] +#[doc = " \"description\": \"The full set of configuration options and their current values.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOption\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ConfigOptionUpdate { + #[doc = "The full set of configuration options and their current values."] + #[serde(rename = "configOptions")] + pub config_options: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ConfigOptionUpdate { + pub fn builder() -> builder::ConfigOptionUpdate { + Default::default() + } +} +#[doc = "Standard content block (text, images, resources)."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Standard content block (text, images, resources).\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"content\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"The actual content block.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ContentBlock\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Content { + #[doc = "The actual content block."] + pub content: ContentBlock, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl Content { + pub fn builder() -> builder::Content { + Default::default() + } +} +#[doc = "Content blocks represent displayable information in the Agent Client Protocol.\n\nThey provide a structured way to handle various types of user-facing content—whether\nit's text from language models, images for analysis, or embedded resources for context.\n\nContent blocks appear in:\n- User prompts sent via `session/prompt`\n- Language model output streamed through `session/update` notifications\n- Progress updates and results from tool calls\n\nThis structure is compatible with the Model Context Protocol (MCP), enabling\nagents to seamlessly forward content from MCP tool outputs without transformation.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/content)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Content blocks represent displayable information in the Agent Client Protocol.\\n\\nThey provide a structured way to handle various types of user-facing content—whether\\nit's text from language models, images for analysis, or embedded resources for context.\\n\\nContent blocks appear in:\\n- User prompts sent via `session/prompt`\\n- Language model output streamed through `session/update` notifications\\n- Progress updates and results from tool calls\\n\\nThis structure is compatible with the Model Context Protocol (MCP), enabling\\nagents to seamlessly forward content from MCP tool outputs without transformation.\\n\\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/content)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"Text content. May be plain text or formatted with Markdown.\\n\\nAll agents MUST support text content blocks in prompts.\\nClients SHOULD render this text as Markdown.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TextContent\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"text\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Images for visual context or analysis.\\n\\nRequires the `image` prompt capability when included in prompts.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ImageContent\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"image\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Audio data for transcription or analysis.\\n\\nRequires the `audio` prompt capability when included in prompts.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AudioContent\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"audio\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"References to resources that the agent can access.\\n\\nAll agents MUST support resource links in prompts.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ResourceLink\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"resource_link\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Complete resource contents embedded directly in the message.\\n\\nPreferred for including context as it avoids extra round-trips.\\n\\nRequires the `embeddedContext` prompt capability when included in prompts.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/EmbeddedResource\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"resource\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"discriminator\": {"] +#[doc = " \"propertyName\": \"type\""] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum ContentBlock { + Variant0 { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + annotations: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Text payload carried by this content block."] + text: ::std::string::String, + #[serde(rename = "type")] + type_: ::std::string::String, + }, + Variant1 { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + annotations: ::std::option::Option, + #[doc = "Base64-encoded media payload."] + data: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde(rename = "mimeType")] + mime_type: ::std::string::String, + #[serde(rename = "type")] + type_: ::std::string::String, + #[doc = "URI associated with this resource or media payload."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + uri: ::std::option::Option<::std::string::String>, + }, + Variant2 { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + annotations: ::std::option::Option, + #[doc = "Base64-encoded media payload."] + data: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde(rename = "mimeType")] + mime_type: ::std::string::String, + #[serde(rename = "type")] + type_: ::std::string::String, + }, + Variant3 { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + annotations: ::std::option::Option, + #[doc = "Optional human-readable details shown with this protocol object."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + description: ::std::option::Option<::std::string::String>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde( + rename = "mimeType", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + mime_type: ::std::option::Option<::std::string::String>, + #[doc = "Human-readable name shown for this protocol object."] + name: ::std::string::String, + #[doc = "Optional size of the linked resource in bytes, if known."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + size: ::std::option::Option, + #[doc = "Optional display title for end-user UI."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + title: ::std::option::Option<::std::string::String>, + #[serde(rename = "type")] + type_: ::std::string::String, + #[doc = "URI associated with this resource or media payload."] + uri: ::std::string::String, + }, + Variant4 { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + annotations: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Embedded resource payload, either text or binary data."] + resource: EmbeddedResourceResource, + #[serde(rename = "type")] + type_: ::std::string::String, + }, +} +#[doc = "A streamed item of content"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A streamed item of content\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"content\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"A single item of content\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ContentBlock\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"messageId\": {"] +#[doc = " \"description\": \"A unique identifier for the message this chunk belongs to.\\n\\nAll chunks belonging to the same message share the same `messageId`.\\nA change in `messageId` indicates a new message has started.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/MessageId\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ContentChunk { + #[doc = "A single item of content"] + pub content: ContentBlock, + #[doc = "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started."] + #[serde( + rename = "messageId", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub message_id: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ContentChunk { + pub fn builder() -> builder::ContentChunk { + Default::default() + } +} +#[doc = "Cost information for a session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Cost information for a session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"amount\","] +#[doc = " \"currency\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"amount\": {"] +#[doc = " \"description\": \"Total cumulative cost for session.\","] +#[doc = " \"type\": \"number\","] +#[doc = " \"format\": \"double\""] +#[doc = " },"] +#[doc = " \"currency\": {"] +#[doc = " \"description\": \"ISO 4217 currency code (e.g., \\\"USD\\\", \\\"EUR\\\").\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Cost { + #[doc = "Total cumulative cost for session."] + pub amount: f64, + #[doc = "ISO 4217 currency code (e.g., \"USD\", \"EUR\")."] + pub currency: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl Cost { + pub fn builder() -> builder::Cost { + Default::default() + } +} +#[doc = "Request to create a new terminal and execute a command."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to create a new terminal and execute a command.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"command\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"args\": {"] +#[doc = " \"description\": \"Array of command arguments.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"command\": {"] +#[doc = " \"description\": \"The command to execute.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"cwd\": {"] +#[doc = " \"description\": \"Working directory for the command. Must be an absolute path.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"env\": {"] +#[doc = " \"description\": \"Environment variables for the command.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/EnvVariable\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"outputByteLimit\": {"] +#[doc = " \"description\": \"Maximum number of output bytes to retain.\\n\\nWhen the limit is exceeded, the Client truncates from the beginning of the output\\nto stay within the limit.\\n\\nThe Client MUST ensure truncation happens at a character boundary to maintain valid\\nstring output, even if this means the retained output is slightly less than the\\nspecified limit.\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"uint64\","] +#[doc = " \"minimum\": 0.0,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/create\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CreateTerminalRequest { + #[doc = "Array of command arguments."] + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub args: ::std::vec::Vec<::std::string::String>, + #[doc = "The command to execute."] + pub command: ::std::string::String, + #[doc = "Working directory for the command. Must be an absolute path."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub cwd: ::std::option::Option<::std::string::String>, + #[doc = "Environment variables for the command."] + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub env: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Maximum number of output bytes to retain.\n\nWhen the limit is exceeded, the Client truncates from the beginning of the output\nto stay within the limit.\n\nThe Client MUST ensure truncation happens at a character boundary to maintain valid\nstring output, even if this means the retained output is slightly less than the\nspecified limit."] + #[serde( + rename = "outputByteLimit", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub output_byte_limit: ::std::option::Option, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl CreateTerminalRequest { + pub fn builder() -> builder::CreateTerminalRequest { + Default::default() + } +} +#[doc = "Response containing the ID of the created terminal."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response containing the ID of the created terminal.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"terminalId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"terminalId\": {"] +#[doc = " \"description\": \"The unique identifier for the created terminal.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/create\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CreateTerminalResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The unique identifier for the created terminal."] + #[serde(rename = "terminalId")] + pub terminal_id: TerminalId, +} +impl CreateTerminalResponse { + pub fn builder() -> builder::CreateTerminalResponse { + Default::default() + } +} +#[doc = "The current mode of the session has changed\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The current mode of the session has changed\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"currentModeId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"currentModeId\": {"] +#[doc = " \"description\": \"The ID of the current mode\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct CurrentModeUpdate { + #[doc = "The ID of the current mode"] + #[serde(rename = "currentModeId")] + pub current_mode_id: SessionModeId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl CurrentModeUpdate { + pub fn builder() -> builder::CurrentModeUpdate { + Default::default() + } +} +#[doc = "Request parameters for deleting an existing session from `session/list`.\n\nOnly available if the Agent supports the `sessionCapabilities.delete` capability."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for deleting an existing session from `session/list`.\\n\\nOnly available if the Agent supports the `sessionCapabilities.delete` capability.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to delete.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/delete\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct DeleteSessionRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to delete."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl DeleteSessionRequest { + pub fn builder() -> builder::DeleteSessionRequest { + Default::default() + } +} +#[doc = "Response from deleting a session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from deleting a session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/delete\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct DeleteSessionResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for DeleteSessionResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl DeleteSessionResponse { + pub fn builder() -> builder::DeleteSessionResponse { + Default::default() + } +} +#[doc = "A diff representing file modifications.\n\nShows changes to files in a format suitable for display in the client UI.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A diff representing file modifications.\\n\\nShows changes to files in a format suitable for display in the client UI.\\n\\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"newText\","] +#[doc = " \"path\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"newText\": {"] +#[doc = " \"description\": \"The new content after modification.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"oldText\": {"] +#[doc = " \"description\": \"The original content (None for new files).\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"path\": {"] +#[doc = " \"description\": \"The absolute file path being modified.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Diff { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The new content after modification."] + #[serde(rename = "newText")] + pub new_text: ::std::string::String, + #[doc = "The original content (None for new files)."] + #[serde( + rename = "oldText", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub old_text: ::std::option::Option<::std::string::String>, + #[doc = "The absolute file path being modified."] + pub path: ::std::string::String, +} +impl Diff { + pub fn builder() -> builder::Diff { + Default::default() + } +} +#[doc = "The contents of a resource, embedded into a prompt or tool call result."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The contents of a resource, embedded into a prompt or tool call result.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"resource\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"annotations\": {"] +#[doc = " \"description\": \"Optional annotations that help clients decide how to display or route this content.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Annotations\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"resource\": {"] +#[doc = " \"description\": \"Embedded resource payload, either text or binary data.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/EmbeddedResourceResource\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct EmbeddedResource { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub annotations: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Embedded resource payload, either text or binary data."] + pub resource: EmbeddedResourceResource, +} +impl EmbeddedResource { + pub fn builder() -> builder::EmbeddedResource { + Default::default() + } +} +#[doc = "Resource content that can be embedded in a message."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Resource content that can be embedded in a message.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"TextResourceContents\","] +#[doc = " \"description\": \"Text resource contents embedded directly in the message.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TextResourceContents\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"BlobResourceContents\","] +#[doc = " \"description\": \"Binary resource contents embedded directly in the message.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/BlobResourceContents\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct EmbeddedResourceResource { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, +} +impl ::std::default::Default for EmbeddedResourceResource { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + } + } +} +impl EmbeddedResourceResource { + pub fn builder() -> builder::EmbeddedResourceResource { + Default::default() + } +} +#[doc = "An environment variable to set when launching an MCP server."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"An environment variable to set when launching an MCP server.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"name\","] +#[doc = " \"value\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"The name of the environment variable.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"value\": {"] +#[doc = " \"description\": \"The value to set for the environment variable.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct EnvVariable { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The name of the environment variable."] + pub name: ::std::string::String, + #[doc = "The value to set for the environment variable."] + pub value: ::std::string::String, +} +impl EnvVariable { + pub fn builder() -> builder::EnvVariable { + Default::default() + } +} +#[doc = "JSON-RPC error object.\n\nRepresents an error that occurred during method execution, following the\nJSON-RPC 2.0 error object specification with optional additional data.\n\nSee protocol docs: [JSON-RPC Error Object](https://www.jsonrpc.org/specification#error_object)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"JSON-RPC error object.\\n\\nRepresents an error that occurred during method execution, following the\\nJSON-RPC 2.0 error object specification with optional additional data.\\n\\nSee protocol docs: [JSON-RPC Error Object](https://www.jsonrpc.org/specification#error_object)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"code\","] +#[doc = " \"message\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"code\": {"] +#[doc = " \"description\": \"A number indicating the error type that occurred.\\nThis must be an integer as defined in the JSON-RPC specification.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ErrorCode\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"data\": {"] +#[doc = " \"description\": \"Optional primitive or structured value that contains additional information about the error.\\nThis may include debugging information or context-specific details.\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"message\": {"] +#[doc = " \"description\": \"A string providing a short description of the error.\\nThe message should be limited to a concise single sentence.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Error { + #[doc = "A number indicating the error type that occurred.\nThis must be an integer as defined in the JSON-RPC specification."] + pub code: ErrorCode, + #[doc = "Optional primitive or structured value that contains additional information about the error.\nThis may include debugging information or context-specific details."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub data: ::std::option::Option<::serde_json::Value>, + #[doc = "A string providing a short description of the error.\nThe message should be limited to a concise single sentence."] + pub message: ::std::string::String, +} +impl Error { + pub fn builder() -> builder::Error { + Default::default() + } +} +#[doc = "Predefined error codes for common JSON-RPC and ACP-specific errors.\n\nThese codes follow the JSON-RPC 2.0 specification for standard errors\nand use the reserved range (-32000 to -32099) for protocol-specific errors."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Predefined error codes for common JSON-RPC and ACP-specific errors.\\n\\nThese codes follow the JSON-RPC 2.0 specification for standard errors\\nand use the reserved range (-32000 to -32099) for protocol-specific errors.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Parse error\","] +#[doc = " \"description\": \"**Parse error**: Invalid JSON was received by the server.\\nAn error occurred on the server while parsing the JSON text.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32700"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Invalid request\","] +#[doc = " \"description\": \"**Invalid request**: The JSON sent is not a valid Request object.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32600"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Method not found\","] +#[doc = " \"description\": \"**Method not found**: The method does not exist or is not available.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32601"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Invalid params\","] +#[doc = " \"description\": \"**Invalid params**: Invalid method parameter(s).\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32602"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Internal error\","] +#[doc = " \"description\": \"**Internal error**: Internal JSON-RPC error.\\nReserved for implementation-defined server errors.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32603"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Request cancelled\","] +#[doc = " \"description\": \"**Request cancelled**: Execution of the method was aborted either due to a cancellation request from the caller or\\nbecause of resource constraints or shutdown.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32800"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Authentication required\","] +#[doc = " \"description\": \"**Authentication required**: Authentication is required before this operation can be performed.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32000"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Resource not found\","] +#[doc = " \"description\": \"**Resource not found**: A given resource, such as a file, was not found.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\","] +#[doc = " \"const\": -32002"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Other\","] +#[doc = " \"description\": \"Other undefined error code.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int32\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ErrorCode { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_5: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_6: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_7: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_8: ::std::option::Option, +} +impl ::std::default::Default for ErrorCode { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + subtype_5: Default::default(), + subtype_6: Default::default(), + subtype_7: Default::default(), + subtype_8: Default::default(), + } + } +} +impl ErrorCode { + pub fn builder() -> builder::ErrorCode { + Default::default() + } +} +#[doc = "Allows the Agent to send an arbitrary notification that is not part of the ACP spec.\nExtension notifications provide a way to send one-way messages for custom functionality\nwhile maintaining protocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Allows the Agent to send an arbitrary notification that is not part of the ACP spec.\\nExtension notifications provide a way to send one-way messages for custom functionality\\nwhile maintaining protocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct ExtNotification(pub ::serde_json::Value); +impl ::std::ops::Deref for ExtNotification { + type Target = ::serde_json::Value; + fn deref(&self) -> &::serde_json::Value { + &self.0 + } +} +impl ::std::convert::From for ::serde_json::Value { + fn from(value: ExtNotification) -> Self { + value.0 + } +} +impl ::std::convert::From<::serde_json::Value> for ExtNotification { + fn from(value: ::serde_json::Value) -> Self { + Self(value) + } +} +#[doc = "Allows for sending an arbitrary request that is not part of the ACP spec.\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Allows for sending an arbitrary request that is not part of the ACP spec.\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct ExtRequest(pub ::serde_json::Value); +impl ::std::ops::Deref for ExtRequest { + type Target = ::serde_json::Value; + fn deref(&self) -> &::serde_json::Value { + &self.0 + } +} +impl ::std::convert::From for ::serde_json::Value { + fn from(value: ExtRequest) -> Self { + value.0 + } +} +impl ::std::convert::From<::serde_json::Value> for ExtRequest { + fn from(value: ::serde_json::Value) -> Self { + Self(value) + } +} +#[doc = "Allows for sending an arbitrary response to an [`ExtRequest`] that is not part of the ACP spec.\nExtension methods provide a way to add custom functionality while maintaining\nprotocol compatibility.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Allows for sending an arbitrary response to an [`ExtRequest`] that is not part of the ACP spec.\\nExtension methods provide a way to add custom functionality while maintaining\\nprotocol compatibility.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct ExtResponse(pub ::serde_json::Value); +impl ::std::ops::Deref for ExtResponse { + type Target = ::serde_json::Value; + fn deref(&self) -> &::serde_json::Value { + &self.0 + } +} +impl ::std::convert::From for ::serde_json::Value { + fn from(value: ExtResponse) -> Self { + value.0 + } +} +impl ::std::convert::From<::serde_json::Value> for ExtResponse { + fn from(value: ::serde_json::Value) -> Self { + Self(value) + } +} +#[doc = "File system capabilities that a client may support.\n\nSee protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"File system capabilities that a client may support.\\n\\nSee protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"readTextFile\": {"] +#[doc = " \"description\": \"Whether the Client supports `fs/read_text_file` requests.\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"writeTextFile\": {"] +#[doc = " \"description\": \"Whether the Client supports `fs/write_text_file` requests.\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct FileSystemCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Whether the Client supports `fs/read_text_file` requests."] + #[serde(rename = "readTextFile", default)] + pub read_text_file: bool, + #[doc = "Whether the Client supports `fs/write_text_file` requests."] + #[serde(rename = "writeTextFile", default)] + pub write_text_file: bool, +} +impl ::std::default::Default for FileSystemCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + read_text_file: Default::default(), + write_text_file: Default::default(), + } + } +} +impl FileSystemCapabilities { + pub fn builder() -> builder::FileSystemCapabilities { + Default::default() + } +} +#[doc = "An HTTP header to set when making requests to the MCP server."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"An HTTP header to set when making requests to the MCP server.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"name\","] +#[doc = " \"value\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"The name of the HTTP header.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"value\": {"] +#[doc = " \"description\": \"The value to set for the HTTP header.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct HttpHeader { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The name of the HTTP header."] + pub name: ::std::string::String, + #[doc = "The value to set for the HTTP header."] + pub value: ::std::string::String, +} +impl HttpHeader { + pub fn builder() -> builder::HttpHeader { + Default::default() + } +} +#[doc = "An image provided to or from an LLM."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"An image provided to or from an LLM.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"data\","] +#[doc = " \"mimeType\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"annotations\": {"] +#[doc = " \"description\": \"Optional annotations that help clients decide how to display or route this content.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Annotations\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"data\": {"] +#[doc = " \"description\": \"Base64-encoded media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"mimeType\": {"] +#[doc = " \"description\": \"MIME type describing the encoded media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"uri\": {"] +#[doc = " \"description\": \"URI associated with this resource or media payload.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ImageContent { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub annotations: ::std::option::Option, + #[doc = "Base64-encoded media payload."] + pub data: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde(rename = "mimeType")] + pub mime_type: ::std::string::String, + #[doc = "URI associated with this resource or media payload."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub uri: ::std::option::Option<::std::string::String>, +} +impl ImageContent { + pub fn builder() -> builder::ImageContent { + Default::default() + } +} +#[doc = "Metadata about the implementation of the client or agent.\nDescribes the name and version of an ACP implementation, with an optional\ntitle for UI representation."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Metadata about the implementation of the client or agent.\\nDescribes the name and version of an ACP implementation, with an optional\\ntitle for UI representation.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"name\","] +#[doc = " \"version\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Intended for programmatic or logical use, but can be used as a display\\nname fallback if title isn’t present.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"title\": {"] +#[doc = " \"description\": \"Intended for UI and end-user contexts — optimized to be human-readable\\nand easily understood.\\n\\nIf not provided, the name should be used for display.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"version\": {"] +#[doc = " \"description\": \"Version of the implementation. Can be displayed to the user or used\\nfor debugging or metrics purposes. (e.g. \\\"1.0.0\\\").\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Implementation { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Intended for programmatic or logical use, but can be used as a display\nname fallback if title isn’t present."] + pub name: ::std::string::String, + #[doc = "Intended for UI and end-user contexts — optimized to be human-readable\nand easily understood.\n\nIf not provided, the name should be used for display."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub title: ::std::option::Option<::std::string::String>, + #[doc = "Version of the implementation. Can be displayed to the user or used\nfor debugging or metrics purposes. (e.g. \"1.0.0\")."] + pub version: ::std::string::String, +} +impl Implementation { + pub fn builder() -> builder::Implementation { + Default::default() + } +} +#[doc = "Request parameters for the initialize method.\n\nSent by the client to establish connection and negotiate capabilities.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for the initialize method.\\n\\nSent by the client to establish connection and negotiate capabilities.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"protocolVersion\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"clientCapabilities\": {"] +#[doc = " \"description\": \"Capabilities supported by the client.\","] +#[doc = " \"default\": {"] +#[doc = " \"fs\": {"] +#[doc = " \"readTextFile\": false,"] +#[doc = " \"writeTextFile\": false"] +#[doc = " },"] +#[doc = " \"terminal\": false"] +#[doc = " },"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ClientCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"clientInfo\": {"] +#[doc = " \"description\": \"Information about the Client name and version sent to the Agent.\\n\\nNote: in future versions of the protocol, this will be required.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Implementation\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"protocolVersion\": {"] +#[doc = " \"description\": \"The latest protocol version supported by the client.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ProtocolVersion\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"initialize\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct InitializeRequest { + #[doc = "Capabilities supported by the client."] + #[serde( + rename = "clientCapabilities", + default = "defaults::initialize_request_client_capabilities" + )] + pub client_capabilities: ClientCapabilities, + #[doc = "Information about the Client name and version sent to the Agent.\n\nNote: in future versions of the protocol, this will be required."] + #[serde( + rename = "clientInfo", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub client_info: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The latest protocol version supported by the client."] + #[serde(rename = "protocolVersion")] + pub protocol_version: ProtocolVersion, +} +impl InitializeRequest { + pub fn builder() -> builder::InitializeRequest { + Default::default() + } +} +#[doc = "Response to the `initialize` method.\n\nContains the negotiated protocol version and agent capabilities.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to the `initialize` method.\\n\\nContains the negotiated protocol version and agent capabilities.\\n\\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"protocolVersion\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"agentCapabilities\": {"] +#[doc = " \"description\": \"Capabilities supported by the agent.\","] +#[doc = " \"default\": {"] +#[doc = " \"auth\": {},"] +#[doc = " \"loadSession\": false,"] +#[doc = " \"mcpCapabilities\": {"] +#[doc = " \"http\": false,"] +#[doc = " \"sse\": false"] +#[doc = " },"] +#[doc = " \"promptCapabilities\": {"] +#[doc = " \"audio\": false,"] +#[doc = " \"embeddedContext\": false,"] +#[doc = " \"image\": false"] +#[doc = " },"] +#[doc = " \"sessionCapabilities\": {}"] +#[doc = " },"] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AgentCapabilities\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"agentInfo\": {"] +#[doc = " \"description\": \"Information about the Agent name and version sent to the Client.\\n\\nNote: in future versions of the protocol, this will be required.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Implementation\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"authMethods\": {"] +#[doc = " \"description\": \"Authentication methods supported by the agent.\","] +#[doc = " \"default\": [],"] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/AuthMethod\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"protocolVersion\": {"] +#[doc = " \"description\": \"The protocol version the client specified if supported by the agent,\\nor the latest protocol version supported by the agent.\\n\\nThe client should disconnect, if it doesn't support this version.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ProtocolVersion\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"initialize\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct InitializeResponse { + #[doc = "Capabilities supported by the agent."] + #[serde( + rename = "agentCapabilities", + default = "defaults::initialize_response_agent_capabilities" + )] + pub agent_capabilities: AgentCapabilities, + #[doc = "Information about the Agent name and version sent to the Client.\n\nNote: in future versions of the protocol, this will be required."] + #[serde( + rename = "agentInfo", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub agent_info: ::std::option::Option, + #[doc = "Authentication methods supported by the agent."] + #[serde( + rename = "authMethods", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub auth_methods: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The protocol version the client specified if supported by the agent,\nor the latest protocol version supported by the agent.\n\nThe client should disconnect, if it doesn't support this version."] + #[serde(rename = "protocolVersion")] + pub protocol_version: ProtocolVersion, +} +impl InitializeResponse { + pub fn builder() -> builder::InitializeResponse { + Default::default() + } +} +#[doc = "Request to kill a terminal without releasing it."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to kill a terminal without releasing it.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\","] +#[doc = " \"terminalId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"terminalId\": {"] +#[doc = " \"description\": \"The ID of the terminal to kill.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/kill\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct KillTerminalRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "The ID of the terminal to kill."] + #[serde(rename = "terminalId")] + pub terminal_id: TerminalId, +} +impl KillTerminalRequest { + pub fn builder() -> builder::KillTerminalRequest { + Default::default() + } +} +#[doc = "Response to `terminal/kill` method"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to `terminal/kill` method\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/kill\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct KillTerminalResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for KillTerminalResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl KillTerminalResponse { + pub fn builder() -> builder::KillTerminalResponse { + Default::default() + } +} +#[doc = "Request parameters for listing existing sessions.\n\nOnly available if the Agent supports the `sessionCapabilities.list` capability."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for listing existing sessions.\\n\\nOnly available if the Agent supports the `sessionCapabilities.list` capability.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"cursor\": {"] +#[doc = " \"description\": \"Opaque cursor token from a previous response's nextCursor field for cursor-based pagination\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"cwd\": {"] +#[doc = " \"description\": \"Filter sessions by working directory. Must be an absolute path.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/list\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ListSessionsRequest { + #[doc = "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination"] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub cursor: ::std::option::Option<::std::string::String>, + #[doc = "Filter sessions by working directory. Must be an absolute path."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub cwd: ::std::option::Option<::std::string::String>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for ListSessionsRequest { + fn default() -> Self { + Self { + cursor: Default::default(), + cwd: Default::default(), + meta: Default::default(), + } + } +} +impl ListSessionsRequest { + pub fn builder() -> builder::ListSessionsRequest { + Default::default() + } +} +#[doc = "Response from listing sessions."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from listing sessions.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessions\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"nextCursor\": {"] +#[doc = " \"description\": \"Opaque cursor token. If present, pass this in the next request's cursor parameter\\nto fetch the next page. If absent, there are no more results.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessions\": {"] +#[doc = " \"description\": \"Array of session information objects\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionInfo\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/list\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ListSessionsResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Opaque cursor token. If present, pass this in the next request's cursor parameter\nto fetch the next page. If absent, there are no more results."] + #[serde( + rename = "nextCursor", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub next_cursor: ::std::option::Option<::std::string::String>, + #[doc = "Array of session information objects"] + pub sessions: ::std::vec::Vec, +} +impl ListSessionsResponse { + pub fn builder() -> builder::ListSessionsResponse { + Default::default() + } +} +#[doc = "Request parameters for loading an existing session.\n\nOnly available if the Agent supports the `loadSession` capability.\n\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for loading an existing session.\\n\\nOnly available if the Agent supports the `loadSession` capability.\\n\\nSee protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"cwd\","] +#[doc = " \"mcpServers\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"additionalDirectories\": {"] +#[doc = " \"description\": \"Additional workspace roots to activate for this session. Each path must be absolute.\\n\\nWhen omitted or empty, no additional roots are activated. When non-empty,\\nthis is the complete resulting additional-root list for the loaded\\nsession. It may differ from any previously used or reported list as long as\\nthe request `cwd` matches the session's `cwd`.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"cwd\": {"] +#[doc = " \"description\": \"The working directory for this session. Must be an absolute path.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"mcpServers\": {"] +#[doc = " \"description\": \"List of MCP servers to connect to for this session.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/McpServer\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to load.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/load\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct LoadSessionRequest { + #[doc = "Additional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`."] + #[serde( + rename = "additionalDirectories", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub additional_directories: ::std::vec::Vec<::std::string::String>, + #[doc = "The working directory for this session. Must be an absolute path."] + pub cwd: ::std::string::String, + #[doc = "List of MCP servers to connect to for this session."] + #[serde(rename = "mcpServers")] + pub mcp_servers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to load."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl LoadSessionRequest { + pub fn builder() -> builder::LoadSessionRequest { + Default::default() + } +} +#[doc = "Response from loading an existing session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from loading an existing session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configOptions\": {"] +#[doc = " \"description\": \"Initial session configuration options if supported by the Agent.\","] +#[doc = " \"type\": ["] +#[doc = " \"array\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOption\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"modes\": {"] +#[doc = " \"description\": \"Initial mode state if supported by the Agent\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeState\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/load\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct LoadSessionResponse { + #[doc = "Initial session configuration options if supported by the Agent."] + #[serde( + rename = "configOptions", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub config_options: ::std::option::Option<::std::vec::Vec>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)"] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub modes: ::std::option::Option, +} +impl ::std::default::Default for LoadSessionResponse { + fn default() -> Self { + Self { + config_options: Default::default(), + meta: Default::default(), + modes: Default::default(), + } + } +} +impl LoadSessionResponse { + pub fn builder() -> builder::LoadSessionResponse { + Default::default() + } +} +#[doc = "Logout capabilities supported by the agent.\n\nSupplying `{}` means the agent supports the logout method."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Logout capabilities supported by the agent.\\n\\nSupplying `{}` means the agent supports the logout method.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct LogoutCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for LogoutCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl LogoutCapabilities { + pub fn builder() -> builder::LogoutCapabilities { + Default::default() + } +} +#[doc = "Request parameters for the logout method.\n\nTerminates the current authenticated session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for the logout method.\\n\\nTerminates the current authenticated session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"logout\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct LogoutRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for LogoutRequest { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl LogoutRequest { + pub fn builder() -> builder::LogoutRequest { + Default::default() + } +} +#[doc = "Response to the `logout` method."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to the `logout` method.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"logout\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct LogoutResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for LogoutResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl LogoutResponse { + pub fn builder() -> builder::LogoutResponse { + Default::default() + } +} +#[doc = "MCP capabilities supported by the agent"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"MCP capabilities supported by the agent\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"http\": {"] +#[doc = " \"description\": \"Agent supports [`McpServer::Http`].\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sse\": {"] +#[doc = " \"description\": \"Agent supports [`McpServer::Sse`].\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpCapabilities { + #[doc = "Agent supports [`McpServer::Http`]."] + #[serde(default)] + pub http: bool, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Agent supports [`McpServer::Sse`]."] + #[serde(default)] + pub sse: bool, +} +impl ::std::default::Default for McpCapabilities { + fn default() -> Self { + Self { + http: Default::default(), + meta: Default::default(), + sse: Default::default(), + } + } +} +impl McpCapabilities { + pub fn builder() -> builder::McpCapabilities { + Default::default() + } +} +#[doc = "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Configuration for connecting to an MCP (Model Context Protocol) server.\\n\\nMCP servers provide tools and context that the agent can use when\\nprocessing prompts.\\n\\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"HTTP transport configuration\\n\\nOnly available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/McpServerHttp\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"http\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"SSE transport configuration\\n\\nOnly available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/McpServerSse\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"sse\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"stdio\","] +#[doc = " \"description\": \"Stdio transport configuration\\n\\nAll Agents MUST support this transport.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/McpServerStdio\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpServer { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, +} +impl ::std::default::Default for McpServer { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + } + } +} +impl McpServer { + pub fn builder() -> builder::McpServer { + Default::default() + } +} +#[doc = "HTTP transport configuration for MCP."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"HTTP transport configuration for MCP.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"headers\","] +#[doc = " \"name\","] +#[doc = " \"url\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"headers\": {"] +#[doc = " \"description\": \"HTTP headers to set when making requests to the MCP server.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/HttpHeader\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable name identifying this MCP server.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"url\": {"] +#[doc = " \"description\": \"URL to the MCP server.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpServerHttp { + #[doc = "HTTP headers to set when making requests to the MCP server."] + pub headers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name identifying this MCP server."] + pub name: ::std::string::String, + #[doc = "URL to the MCP server."] + pub url: ::std::string::String, +} +impl McpServerHttp { + pub fn builder() -> builder::McpServerHttp { + Default::default() + } +} +#[doc = "SSE transport configuration for MCP."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"SSE transport configuration for MCP.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"headers\","] +#[doc = " \"name\","] +#[doc = " \"url\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"headers\": {"] +#[doc = " \"description\": \"HTTP headers to set when making requests to the MCP server.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/HttpHeader\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable name identifying this MCP server.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"url\": {"] +#[doc = " \"description\": \"URL to the MCP server.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpServerSse { + #[doc = "HTTP headers to set when making requests to the MCP server."] + pub headers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name identifying this MCP server."] + pub name: ::std::string::String, + #[doc = "URL to the MCP server."] + pub url: ::std::string::String, +} +impl McpServerSse { + pub fn builder() -> builder::McpServerSse { + Default::default() + } +} +#[doc = "Stdio transport configuration for MCP."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Stdio transport configuration for MCP.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"args\","] +#[doc = " \"command\","] +#[doc = " \"env\","] +#[doc = " \"name\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"args\": {"] +#[doc = " \"description\": \"Command-line arguments to pass to the MCP server.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"command\": {"] +#[doc = " \"description\": \"Absolute path to the MCP server executable.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"env\": {"] +#[doc = " \"description\": \"Environment variables to set when launching the MCP server.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/EnvVariable\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable name identifying this MCP server.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpServerStdio { + #[doc = "Command-line arguments to pass to the MCP server."] + pub args: ::std::vec::Vec<::std::string::String>, + #[doc = "Absolute path to the MCP server executable."] + pub command: ::std::string::String, + #[doc = "Environment variables to set when launching the MCP server."] + pub env: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name identifying this MCP server."] + pub name: ::std::string::String, +} +impl McpServerStdio { + pub fn builder() -> builder::McpServerStdio { + Default::default() + } +} +#[doc = "HTTP transport configuration\n\nOnly available when the Agent capabilities indicate `mcp_capabilities.http` is `true`."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"HTTP transport configuration\\n\\nOnly available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/McpServerHttp\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"http\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpServerSubtype0 { + #[doc = "HTTP headers to set when making requests to the MCP server."] + pub headers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name identifying this MCP server."] + pub name: ::std::string::String, + #[serde(rename = "type")] + pub type_: ::std::string::String, + #[doc = "URL to the MCP server."] + pub url: ::std::string::String, +} +impl McpServerSubtype0 { + pub fn builder() -> builder::McpServerSubtype0 { + Default::default() + } +} +#[doc = "SSE transport configuration\n\nOnly available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"SSE transport configuration\\n\\nOnly available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/McpServerSse\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"sse\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct McpServerSubtype1 { + #[doc = "HTTP headers to set when making requests to the MCP server."] + pub headers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name identifying this MCP server."] + pub name: ::std::string::String, + #[serde(rename = "type")] + pub type_: ::std::string::String, + #[doc = "URL to the MCP server."] + pub url: ::std::string::String, +} +impl McpServerSubtype1 { + pub fn builder() -> builder::McpServerSubtype1 { + Default::default() + } +} +#[doc = "Unique identifier for a message within a session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a message within a session.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct MessageId(pub ::std::string::String); +impl ::std::ops::Deref for MessageId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: MessageId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for MessageId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for MessageId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for MessageId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Request parameters for creating a new session.\n\nSee protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for creating a new session.\\n\\nSee protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"cwd\","] +#[doc = " \"mcpServers\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"additionalDirectories\": {"] +#[doc = " \"description\": \"Additional workspace roots for this session. Each path must be absolute.\\n\\nThese expand the session's filesystem scope without changing `cwd`, which\\nremains the base for relative paths. When omitted or empty, no\\nadditional roots are activated for the new session.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"cwd\": {"] +#[doc = " \"description\": \"The working directory for this session. Must be an absolute path.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"mcpServers\": {"] +#[doc = " \"description\": \"List of MCP (Model Context Protocol) servers the agent should connect to.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/McpServer\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/new\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct NewSessionRequest { + #[doc = "Additional workspace roots for this session. Each path must be absolute.\n\nThese expand the session's filesystem scope without changing `cwd`, which\nremains the base for relative paths. When omitted or empty, no\nadditional roots are activated for the new session."] + #[serde( + rename = "additionalDirectories", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub additional_directories: ::std::vec::Vec<::std::string::String>, + #[doc = "The working directory for this session. Must be an absolute path."] + pub cwd: ::std::string::String, + #[doc = "List of MCP (Model Context Protocol) servers the agent should connect to."] + #[serde(rename = "mcpServers")] + pub mcp_servers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl NewSessionRequest { + pub fn builder() -> builder::NewSessionRequest { + Default::default() + } +} +#[doc = "Response from creating a new session.\n\nSee protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from creating a new session.\\n\\nSee protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configOptions\": {"] +#[doc = " \"description\": \"Initial session configuration options if supported by the Agent.\","] +#[doc = " \"type\": ["] +#[doc = " \"array\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOption\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"modes\": {"] +#[doc = " \"description\": \"Initial mode state if supported by the Agent\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeState\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"Unique identifier for the created session.\\n\\nUsed in all subsequent requests for this conversation.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/new\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct NewSessionResponse { + #[doc = "Initial session configuration options if supported by the Agent."] + #[serde( + rename = "configOptions", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub config_options: ::std::option::Option<::std::vec::Vec>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)"] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub modes: ::std::option::Option, + #[doc = "Unique identifier for the created session.\n\nUsed in all subsequent requests for this conversation."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl NewSessionResponse { + pub fn builder() -> builder::NewSessionResponse { + Default::default() + } +} +#[doc = "An option presented to the user when requesting permission."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"An option presented to the user when requesting permission.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"kind\","] +#[doc = " \"name\","] +#[doc = " \"optionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"kind\": {"] +#[doc = " \"description\": \"Hint about the nature of this permission option.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PermissionOptionKind\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable label to display to the user.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"optionId\": {"] +#[doc = " \"description\": \"Unique identifier for this permission option.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PermissionOptionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct PermissionOption { + #[doc = "Hint about the nature of this permission option."] + pub kind: PermissionOptionKind, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable label to display to the user."] + pub name: ::std::string::String, + #[doc = "Unique identifier for this permission option."] + #[serde(rename = "optionId")] + pub option_id: PermissionOptionId, +} +impl PermissionOption { + pub fn builder() -> builder::PermissionOption { + Default::default() + } +} +#[doc = "Unique identifier for a permission option."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a permission option.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct PermissionOptionId(pub ::std::string::String); +impl ::std::ops::Deref for PermissionOptionId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: PermissionOptionId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for PermissionOptionId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for PermissionOptionId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for PermissionOptionId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "The type of permission option being presented to the user.\n\nHelps clients choose appropriate icons and UI treatment."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The type of permission option being presented to the user.\\n\\nHelps clients choose appropriate icons and UI treatment.\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"Allow this operation only this time.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"allow_once\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Allow this operation and remember the choice.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"allow_always\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Reject this operation only this time.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"reject_once\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Reject this operation and remember the choice.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"reject_always\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum PermissionOptionKind { + #[doc = "Allow this operation only this time."] + #[serde(rename = "allow_once")] + AllowOnce, + #[doc = "Allow this operation and remember the choice."] + #[serde(rename = "allow_always")] + AllowAlways, + #[doc = "Reject this operation only this time."] + #[serde(rename = "reject_once")] + RejectOnce, + #[doc = "Reject this operation and remember the choice."] + #[serde(rename = "reject_always")] + RejectAlways, +} +impl ::std::fmt::Display for PermissionOptionKind { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::AllowOnce => f.write_str("allow_once"), + Self::AllowAlways => f.write_str("allow_always"), + Self::RejectOnce => f.write_str("reject_once"), + Self::RejectAlways => f.write_str("reject_always"), + } + } +} +impl ::std::str::FromStr for PermissionOptionKind { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "allow_once" => Ok(Self::AllowOnce), + "allow_always" => Ok(Self::AllowAlways), + "reject_once" => Ok(Self::RejectOnce), + "reject_always" => Ok(Self::RejectAlways), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for PermissionOptionKind { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for PermissionOptionKind { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for PermissionOptionKind { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "An execution plan for accomplishing complex tasks.\n\nPlans consist of multiple entries representing individual tasks or goals.\nAgents report plans to clients to provide visibility into their execution strategy.\nPlans can evolve during execution as the agent discovers new requirements or completes tasks.\n\nSee protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"An execution plan for accomplishing complex tasks.\\n\\nPlans consist of multiple entries representing individual tasks or goals.\\nAgents report plans to clients to provide visibility into their execution strategy.\\nPlans can evolve during execution as the agent discovers new requirements or completes tasks.\\n\\nSee protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"entries\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"entries\": {"] +#[doc = " \"description\": \"The list of tasks to be accomplished.\\n\\nWhen updating a plan, the agent must send a complete list of all entries\\nwith their current status. The client replaces the entire plan with each update.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/PlanEntry\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Plan { + #[doc = "The list of tasks to be accomplished.\n\nWhen updating a plan, the agent must send a complete list of all entries\nwith their current status. The client replaces the entire plan with each update."] + pub entries: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl Plan { + pub fn builder() -> builder::Plan { + Default::default() + } +} +#[doc = "A single entry in the execution plan.\n\nRepresents a task or goal that the assistant intends to accomplish\nas part of fulfilling the user's request.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A single entry in the execution plan.\\n\\nRepresents a task or goal that the assistant intends to accomplish\\nas part of fulfilling the user's request.\\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"content\","] +#[doc = " \"priority\","] +#[doc = " \"status\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"Human-readable description of what this task aims to accomplish.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"priority\": {"] +#[doc = " \"description\": \"The relative importance of this task.\\nUsed to indicate which tasks are most critical to the overall goal.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PlanEntryPriority\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"status\": {"] +#[doc = " \"description\": \"Current execution status of this task.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PlanEntryStatus\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct PlanEntry { + #[doc = "Human-readable description of what this task aims to accomplish."] + pub content: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The relative importance of this task.\nUsed to indicate which tasks are most critical to the overall goal."] + pub priority: PlanEntryPriority, + #[doc = "Current execution status of this task."] + pub status: PlanEntryStatus, +} +impl PlanEntry { + pub fn builder() -> builder::PlanEntry { + Default::default() + } +} +#[doc = "Priority levels for plan entries.\n\nUsed to indicate the relative importance or urgency of different\ntasks in the execution plan.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Priority levels for plan entries.\\n\\nUsed to indicate the relative importance or urgency of different\\ntasks in the execution plan.\\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"High priority task - critical to the overall goal.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"high\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Medium priority task - important but not critical.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"medium\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Low priority task - nice to have but not essential.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"low\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum PlanEntryPriority { + #[doc = "High priority task - critical to the overall goal."] + #[serde(rename = "high")] + High, + #[doc = "Medium priority task - important but not critical."] + #[serde(rename = "medium")] + Medium, + #[doc = "Low priority task - nice to have but not essential."] + #[serde(rename = "low")] + Low, +} +impl ::std::fmt::Display for PlanEntryPriority { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::High => f.write_str("high"), + Self::Medium => f.write_str("medium"), + Self::Low => f.write_str("low"), + } + } +} +impl ::std::str::FromStr for PlanEntryPriority { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "high" => Ok(Self::High), + "medium" => Ok(Self::Medium), + "low" => Ok(Self::Low), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for PlanEntryPriority { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for PlanEntryPriority { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for PlanEntryPriority { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "Status of a plan entry in the execution flow.\n\nTracks the lifecycle of each task from planning through completion.\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Status of a plan entry in the execution flow.\\n\\nTracks the lifecycle of each task from planning through completion.\\nSee protocol docs: [Plan Entries](https://agentclientprotocol.com/protocol/agent-plan#plan-entries)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"The task has not started yet.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"pending\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The task is currently being worked on.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"in_progress\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The task has been successfully completed.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"completed\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum PlanEntryStatus { + #[doc = "The task has not started yet."] + #[serde(rename = "pending")] + Pending, + #[doc = "The task is currently being worked on."] + #[serde(rename = "in_progress")] + InProgress, + #[doc = "The task has been successfully completed."] + #[serde(rename = "completed")] + Completed, +} +impl ::std::fmt::Display for PlanEntryStatus { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::Pending => f.write_str("pending"), + Self::InProgress => f.write_str("in_progress"), + Self::Completed => f.write_str("completed"), + } + } +} +impl ::std::str::FromStr for PlanEntryStatus { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "pending" => Ok(Self::Pending), + "in_progress" => Ok(Self::InProgress), + "completed" => Ok(Self::Completed), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for PlanEntryStatus { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for PlanEntryStatus { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for PlanEntryStatus { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "Prompt capabilities supported by the agent in `session/prompt` requests.\n\nBaseline agent functionality requires support for [`ContentBlock::Text`]\nand [`ContentBlock::ResourceLink`] in prompt requests.\n\nOther variants must be explicitly opted in to.\nCapabilities for different types of content in prompt requests.\n\nIndicates which content types beyond the baseline (text and resource links)\nthe agent can process.\n\nSee protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Prompt capabilities supported by the agent in `session/prompt` requests.\\n\\nBaseline agent functionality requires support for [`ContentBlock::Text`]\\nand [`ContentBlock::ResourceLink`] in prompt requests.\\n\\nOther variants must be explicitly opted in to.\\nCapabilities for different types of content in prompt requests.\\n\\nIndicates which content types beyond the baseline (text and resource links)\\nthe agent can process.\\n\\nSee protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"audio\": {"] +#[doc = " \"description\": \"Agent supports [`ContentBlock::Audio`].\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"embeddedContext\": {"] +#[doc = " \"description\": \"Agent supports embedded context in `session/prompt` requests.\\n\\nWhen enabled, the Client is allowed to include [`ContentBlock::Resource`]\\nin prompt requests for pieces of context that are referenced in the message.\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"image\": {"] +#[doc = " \"description\": \"Agent supports [`ContentBlock::Image`].\","] +#[doc = " \"default\": false,"] +#[doc = " \"type\": \"boolean\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct PromptCapabilities { + #[doc = "Agent supports [`ContentBlock::Audio`]."] + #[serde(default)] + pub audio: bool, + #[doc = "Agent supports embedded context in `session/prompt` requests.\n\nWhen enabled, the Client is allowed to include [`ContentBlock::Resource`]\nin prompt requests for pieces of context that are referenced in the message."] + #[serde(rename = "embeddedContext", default)] + pub embedded_context: bool, + #[doc = "Agent supports [`ContentBlock::Image`]."] + #[serde(default)] + pub image: bool, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for PromptCapabilities { + fn default() -> Self { + Self { + audio: Default::default(), + embedded_context: Default::default(), + image: Default::default(), + meta: Default::default(), + } + } +} +impl PromptCapabilities { + pub fn builder() -> builder::PromptCapabilities { + Default::default() + } +} +#[doc = "Request parameters for sending a user prompt to the agent.\n\nContains the user's message and any additional context.\n\nSee protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for sending a user prompt to the agent.\\n\\nContains the user's message and any additional context.\\n\\nSee protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"prompt\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"prompt\": {"] +#[doc = " \"description\": \"The blocks of content that compose the user's message.\\n\\nAs a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],\\nwhile other variants are optionally enabled via [`PromptCapabilities`].\\n\\nThe Client MUST adapt its interface according to [`PromptCapabilities`].\\n\\nThe client MAY include referenced pieces of context as either\\n[`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].\\n\\nWhen available, [`ContentBlock::Resource`] is preferred\\nas it avoids extra round-trips and allows the message to include\\npieces of context from sources the agent may not have access to.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/ContentBlock\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to send this user message to\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/prompt\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct PromptRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The blocks of content that compose the user's message.\n\nAs a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],\nwhile other variants are optionally enabled via [`PromptCapabilities`].\n\nThe Client MUST adapt its interface according to [`PromptCapabilities`].\n\nThe client MAY include referenced pieces of context as either\n[`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].\n\nWhen available, [`ContentBlock::Resource`] is preferred\nas it avoids extra round-trips and allows the message to include\npieces of context from sources the agent may not have access to."] + pub prompt: ::std::vec::Vec, + #[doc = "The ID of the session to send this user message to"] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl PromptRequest { + pub fn builder() -> builder::PromptRequest { + Default::default() + } +} +#[doc = "Response from processing a user prompt.\n\nSee protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from processing a user prompt.\\n\\nSee protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"stopReason\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"stopReason\": {"] +#[doc = " \"description\": \"Indicates why the agent stopped processing the turn.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/StopReason\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/prompt\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct PromptResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Indicates why the agent stopped processing the turn."] + #[serde(rename = "stopReason")] + pub stop_reason: StopReason, +} +impl PromptResponse { + pub fn builder() -> builder::PromptResponse { + Default::default() + } +} +#[doc = "A message (request, response, or notification) with `\"jsonrpc\": \"2.0\"` specified as\n[required by JSON-RPC 2.0 Specification][1].\n\n[1]: https://www.jsonrpc.org/specification#compatibility"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"title\": \"ProtocolLevel\","] +#[doc = " \"description\": \"A message (request, response, or notification) with `\\\"jsonrpc\\\": \\\"2.0\\\"` specified as\\n[required by JSON-RPC 2.0 Specification][1].\\n\\n[1]: https://www.jsonrpc.org/specification#compatibility\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"jsonrpc\","] +#[doc = " \"method\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"jsonrpc\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"method\": {"] +#[doc = " \"description\": \"The notification method name.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"params\": {"] +#[doc = " \"description\": \"Method-specific notification parameters.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"General protocol-level notifications that all sides are expected to\\nimplement.\\n\\nNotifications whose methods start with '$/' are messages which\\nare protocol implementation dependent and might not be implementable in all\\nclients or agents. For example if the implementation uses a single threaded\\nsynchronous programming language then there is little it can do to react to\\na `$/cancel_request` notification. If an agent or client receives\\nnotifications starting with '$/' it is free to ignore the notification.\\n\\nNotifications do not expect a response.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"CancelRequestNotification\","] +#[doc = " \"description\": \"Cancels an ongoing request.\\n\\nThis is a notification sent by the side that sent a request to cancel that request.\\n\\nUpon receiving this notification, the receiver:\\n\\n1. MAY cancel the corresponding request activity and all nested activities\\n2. MAY send any pending notifications.\\n3. MUST send one of these responses for the original request:\\n - Valid response with appropriate data (partial results or cancellation marker)\\n - Error response with code `-32800` (Cancelled)\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/cancellation)\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CancelRequestNotification\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-docs-ignore\": true"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ProtocolLevel { + pub jsonrpc: ProtocolLevelJsonrpc, + #[doc = "The notification method name."] + pub method: ::std::string::String, + #[doc = "Method-specific notification parameters."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub params: ::std::option::Option, +} +impl ProtocolLevel { + pub fn builder() -> builder::ProtocolLevel { + Default::default() + } +} +#[doc = "`ProtocolLevelJsonrpc`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"type\": \"string\","] +#[doc = " \"enum\": ["] +#[doc = " \"2.0\""] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum ProtocolLevelJsonrpc { + #[serde(rename = "2.0")] + X20, +} +impl ::std::fmt::Display for ProtocolLevelJsonrpc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::X20 => f.write_str("2.0"), + } + } +} +impl ::std::str::FromStr for ProtocolLevelJsonrpc { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "2.0" => Ok(Self::X20), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for ProtocolLevelJsonrpc { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for ProtocolLevelJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for ProtocolLevelJsonrpc { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "Protocol version identifier.\n\nThis version is only bumped for breaking changes.\nNon-breaking changes should be introduced via capabilities."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Protocol version identifier.\\n\\nThis version is only bumped for breaking changes.\\nNon-breaking changes should be introduced via capabilities.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"uint16\","] +#[doc = " \"maximum\": 65535.0,"] +#[doc = " \"minimum\": 0.0"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(transparent)] +pub struct ProtocolVersion(pub u16); +impl ::std::ops::Deref for ProtocolVersion { + type Target = u16; + fn deref(&self) -> &u16 { + &self.0 + } +} +impl ::std::convert::From for u16 { + fn from(value: ProtocolVersion) -> Self { + value.0 + } +} +impl ::std::convert::From for ProtocolVersion { + fn from(value: u16) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for ProtocolVersion { + type Err = ::Err; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.parse()?)) + } +} +impl ::std::convert::TryFrom<&str> for ProtocolVersion { + type Error = ::Err; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom for ProtocolVersion { + type Error = ::Err; + fn try_from(value: String) -> ::std::result::Result { + value.parse() + } +} +impl ::std::fmt::Display for ProtocolVersion { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Request to read content from a text file.\n\nOnly available if the client supports the `fs.readTextFile` capability."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to read content from a text file.\\n\\nOnly available if the client supports the `fs.readTextFile` capability.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"path\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"limit\": {"] +#[doc = " \"description\": \"Maximum number of lines to read.\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"uint32\","] +#[doc = " \"minimum\": 0.0,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"line\": {"] +#[doc = " \"description\": \"Line number to start reading from (1-based).\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"uint32\","] +#[doc = " \"minimum\": 0.0,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"path\": {"] +#[doc = " \"description\": \"Absolute path to the file to read.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"fs/read_text_file\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ReadTextFileRequest { + #[doc = "Maximum number of lines to read."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub limit: ::std::option::Option, + #[doc = "Line number to start reading from (1-based)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub line: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Absolute path to the file to read."] + pub path: ::std::string::String, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl ReadTextFileRequest { + pub fn builder() -> builder::ReadTextFileRequest { + Default::default() + } +} +#[doc = "Response containing the contents of a text file."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response containing the contents of a text file.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"content\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"Content payload returned by this response.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"fs/read_text_file\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ReadTextFileResponse { + #[doc = "Content payload returned by this response."] + pub content: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ReadTextFileResponse { + pub fn builder() -> builder::ReadTextFileResponse { + Default::default() + } +} +#[doc = "Request to release a terminal and free its resources."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to release a terminal and free its resources.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\","] +#[doc = " \"terminalId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"terminalId\": {"] +#[doc = " \"description\": \"The ID of the terminal to release.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/release\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ReleaseTerminalRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "The ID of the terminal to release."] + #[serde(rename = "terminalId")] + pub terminal_id: TerminalId, +} +impl ReleaseTerminalRequest { + pub fn builder() -> builder::ReleaseTerminalRequest { + Default::default() + } +} +#[doc = "Response to terminal/release method"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to terminal/release method\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/release\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ReleaseTerminalResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for ReleaseTerminalResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl ReleaseTerminalResponse { + pub fn builder() -> builder::ReleaseTerminalResponse { + Default::default() + } +} +#[doc = "JSON RPC Request Id\n\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null \\[1\\] and Numbers SHOULD NOT contain fractional parts \\[2\\]\n\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\n\n\\[1\\] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\n\n\\[2\\] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"JSON RPC Request Id\\n\\nAn identifier established by the Client that MUST contain a String, Number, or NULL value if included. If it is not included it is assumed to be a notification. The value SHOULD normally not be Null \\\\[1\\\\] and Numbers SHOULD NOT contain fractional parts \\\\[2\\\\]\\n\\nThe Server MUST reply with the same value in the Response object if included. This member is used to correlate the context between the two objects.\\n\\n\\\\[1\\\\] The use of Null as a value for the id member in a Request object is discouraged, because this specification uses a value of Null for Responses with an unknown id. Also, because JSON-RPC 1.0 uses an id value of Null for Notifications this could cause confusion in handling.\\n\\n\\\\[2\\\\] Fractional parts may be problematic, since many decimal fractions cannot be represented exactly as binary fractions.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Null\","] +#[doc = " \"description\": \"The JSON-RPC `null` request id.\","] +#[doc = " \"type\": \"null\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Number\","] +#[doc = " \"description\": \"A numeric JSON-RPC request id.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"int64\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Str\","] +#[doc = " \"description\": \"A string JSON-RPC request id.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum RequestId { + Null, + Number(i64), + Str(::std::string::String), +} +impl ::std::convert::From for RequestId { + fn from(value: i64) -> Self { + Self::Number(value) + } +} +#[doc = "The outcome of a permission request."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The outcome of a permission request.\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"The prompt turn was cancelled before the user responded.\\n\\nWhen a client sends a `session/cancel` notification to cancel an ongoing\\nprompt turn, it MUST respond to all pending `session/request_permission`\\nrequests with this `Cancelled` outcome.\\n\\nSee protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"outcome\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"outcome\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"cancelled\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The user selected one of the provided options.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SelectedPermissionOutcome\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"outcome\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"outcome\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"selected\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"discriminator\": {"] +#[doc = " \"propertyName\": \"outcome\""] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum RequestPermissionOutcome { + Variant0 { + outcome: ::std::string::String, + }, + Variant1 { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the option the user selected."] + #[serde(rename = "optionId")] + option_id: PermissionOptionId, + outcome: ::std::string::String, + }, +} +#[doc = "Request for user permission to execute a tool call.\n\nSent when the agent needs authorization before performing a sensitive operation.\n\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request for user permission to execute a tool call.\\n\\nSent when the agent needs authorization before performing a sensitive operation.\\n\\nSee protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"options\","] +#[doc = " \"sessionId\","] +#[doc = " \"toolCall\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"options\": {"] +#[doc = " \"description\": \"Available permission options for the user to choose from.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/PermissionOption\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"toolCall\": {"] +#[doc = " \"description\": \"Details about the tool call requiring permission.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallUpdate\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/request_permission\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct RequestPermissionRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Available permission options for the user to choose from."] + pub options: ::std::vec::Vec, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "Details about the tool call requiring permission."] + #[serde(rename = "toolCall")] + pub tool_call: ToolCallUpdate, +} +impl RequestPermissionRequest { + pub fn builder() -> builder::RequestPermissionRequest { + Default::default() + } +} +#[doc = "Response to a permission request."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to a permission request.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"outcome\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"outcome\": {"] +#[doc = " \"description\": \"The user's decision on the permission request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/RequestPermissionOutcome\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/request_permission\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct RequestPermissionResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The user's decision on the permission request."] + pub outcome: RequestPermissionOutcome, +} +impl RequestPermissionResponse { + pub fn builder() -> builder::RequestPermissionResponse { + Default::default() + } +} +#[doc = "A resource that the server is capable of reading, included in a prompt or tool call result."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A resource that the server is capable of reading, included in a prompt or tool call result.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"name\","] +#[doc = " \"uri\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"annotations\": {"] +#[doc = " \"description\": \"Optional annotations that help clients decide how to display or route this content.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Annotations\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"description\": {"] +#[doc = " \"description\": \"Optional human-readable details shown with this protocol object.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"mimeType\": {"] +#[doc = " \"description\": \"MIME type describing the encoded media payload.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable name shown for this protocol object.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"size\": {"] +#[doc = " \"description\": \"Optional size of the linked resource in bytes, if known.\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"int64\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"title\": {"] +#[doc = " \"description\": \"Optional display title for end-user UI.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"uri\": {"] +#[doc = " \"description\": \"URI associated with this resource or media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ResourceLink { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub annotations: ::std::option::Option, + #[doc = "Optional human-readable details shown with this protocol object."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub description: ::std::option::Option<::std::string::String>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde( + rename = "mimeType", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub mime_type: ::std::option::Option<::std::string::String>, + #[doc = "Human-readable name shown for this protocol object."] + pub name: ::std::string::String, + #[doc = "Optional size of the linked resource in bytes, if known."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub size: ::std::option::Option, + #[doc = "Optional display title for end-user UI."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub title: ::std::option::Option<::std::string::String>, + #[doc = "URI associated with this resource or media payload."] + pub uri: ::std::string::String, +} +impl ResourceLink { + pub fn builder() -> builder::ResourceLink { + Default::default() + } +} +#[doc = "Method-specific response data."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Method-specific response data.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"InitializeResponse\","] +#[doc = " \"description\": \"Successful result returned for a `initialize` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/InitializeResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"AuthenticateResponse\","] +#[doc = " \"description\": \"Successful result returned for a `authenticate` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AuthenticateResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LogoutResponse\","] +#[doc = " \"description\": \"Successful result returned for a `logout` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LogoutResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"NewSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/new` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/NewSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"LoadSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/load` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/LoadSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ListSessionsResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/list` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ListSessionsResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"DeleteSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/delete` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/DeleteSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ResumeSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/resume` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ResumeSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"CloseSessionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/close` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CloseSessionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionModeResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/set_mode` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionModeResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"SetSessionConfigOptionResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/set_config_option` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SetSessionConfigOptionResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"PromptResponse\","] +#[doc = " \"description\": \"Successful result returned for a `session/prompt` request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PromptResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"ExtMethodResponse\","] +#[doc = " \"description\": \"Successful result returned by an extension method outside the core ACP method set.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ExtResponse\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ResultResult { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_5: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_6: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_7: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_8: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_9: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_10: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_11: ::std::option::Option, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_12: ::std::option::Option, +} +impl ::std::default::Default for ResultResult { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + subtype_5: Default::default(), + subtype_6: Default::default(), + subtype_7: Default::default(), + subtype_8: Default::default(), + subtype_9: Default::default(), + subtype_10: Default::default(), + subtype_11: Default::default(), + subtype_12: Default::default(), + } + } +} +impl ResultResult { + pub fn builder() -> builder::ResultResult { + Default::default() + } +} +#[doc = "Request parameters for resuming an existing session.\n\nResumes an existing session without returning previous messages (unlike `session/load`).\nThis is useful for agents that can resume sessions but don't implement full session loading.\n\nOnly available if the Agent supports the `sessionCapabilities.resume` capability."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for resuming an existing session.\\n\\nResumes an existing session without returning previous messages (unlike `session/load`).\\nThis is useful for agents that can resume sessions but don't implement full session loading.\\n\\nOnly available if the Agent supports the `sessionCapabilities.resume` capability.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"cwd\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"additionalDirectories\": {"] +#[doc = " \"description\": \"Additional workspace roots to activate for this session. Each path must be absolute.\\n\\nWhen omitted or empty, no additional roots are activated. When non-empty,\\nthis is the complete resulting additional-root list for the resumed\\nsession. It may differ from any previously used or reported list as long as\\nthe request `cwd` matches the session's `cwd`.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"cwd\": {"] +#[doc = " \"description\": \"The working directory for this session. Must be an absolute path.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"mcpServers\": {"] +#[doc = " \"description\": \"List of MCP servers to connect to for this session.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/McpServer\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to resume.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/resume\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ResumeSessionRequest { + #[doc = "Additional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`."] + #[serde( + rename = "additionalDirectories", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub additional_directories: ::std::vec::Vec<::std::string::String>, + #[doc = "The working directory for this session. Must be an absolute path."] + pub cwd: ::std::string::String, + #[doc = "List of MCP servers to connect to for this session."] + #[serde( + rename = "mcpServers", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub mcp_servers: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to resume."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl ResumeSessionRequest { + pub fn builder() -> builder::ResumeSessionRequest { + Default::default() + } +} +#[doc = "Response from resuming an existing session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response from resuming an existing session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configOptions\": {"] +#[doc = " \"description\": \"Initial session configuration options if supported by the Agent.\","] +#[doc = " \"type\": ["] +#[doc = " \"array\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOption\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"modes\": {"] +#[doc = " \"description\": \"Initial mode state if supported by the Agent\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeState\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/resume\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ResumeSessionResponse { + #[doc = "Initial session configuration options if supported by the Agent."] + #[serde( + rename = "configOptions", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub config_options: ::std::option::Option<::std::vec::Vec>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Initial mode state if supported by the Agent\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)"] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub modes: ::std::option::Option, +} +impl ::std::default::Default for ResumeSessionResponse { + fn default() -> Self { + Self { + config_options: Default::default(), + meta: Default::default(), + modes: Default::default(), + } + } +} +impl ResumeSessionResponse { + pub fn builder() -> builder::ResumeSessionResponse { + Default::default() + } +} +#[doc = "The sender or recipient of messages and data in a conversation."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The sender or recipient of messages and data in a conversation.\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"The assistant side of a conversation.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"assistant\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The user side of a conversation.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"user\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum Role { + #[doc = "The assistant side of a conversation."] + #[serde(rename = "assistant")] + Assistant, + #[doc = "The user side of a conversation."] + #[serde(rename = "user")] + User, +} +impl ::std::fmt::Display for Role { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::Assistant => f.write_str("assistant"), + Self::User => f.write_str("user"), + } + } +} +impl ::std::str::FromStr for Role { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "assistant" => Ok(Self::Assistant), + "user" => Ok(Self::User), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for Role { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for Role { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for Role { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "The user selected one of the provided options."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The user selected one of the provided options.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"optionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"optionId\": {"] +#[doc = " \"description\": \"The ID of the option the user selected.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/PermissionOptionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SelectedPermissionOutcome { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the option the user selected."] + #[serde(rename = "optionId")] + pub option_id: PermissionOptionId, +} +impl SelectedPermissionOutcome { + pub fn builder() -> builder::SelectedPermissionOutcome { + Default::default() + } +} +#[doc = "Capabilities for additional session directories support.\n\nSupplying `{}` means the agent supports the `additionalDirectories` field on\nsupported session lifecycle requests. Agents that also support\n`session/list` may return `SessionInfo.additionalDirectories` to report the\ncomplete ordered additional-root list associated with a listed session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities for additional session directories support.\\n\\nSupplying `{}` means the agent supports the `additionalDirectories` field on\\nsupported session lifecycle requests. Agents that also support\\n`session/list` may return `SessionInfo.additionalDirectories` to report the\\ncomplete ordered additional-root list associated with a listed session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionAdditionalDirectoriesCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SessionAdditionalDirectoriesCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl SessionAdditionalDirectoriesCapabilities { + pub fn builder() -> builder::SessionAdditionalDirectoriesCapabilities { + Default::default() + } +} +#[doc = "Session capabilities supported by the agent.\n\nAs a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.\n\nOptionally, they **MAY** support other session methods and notifications by specifying additional capabilities.\n\nNote: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.\n\nSee protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Session capabilities supported by the agent.\\n\\nAs a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.\\n\\nOptionally, they **MAY** support other session methods and notifications by specifying additional capabilities.\\n\\nNote: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.\\n\\nSee protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"additionalDirectories\": {"] +#[doc = " \"description\": \"Whether the agent supports `additionalDirectories` on supported session lifecycle requests.\\n\\nOptional. Omitted or `null` both mean the agent does not advertise support.\\nSupplying `{}` means the agent supports `additionalDirectories` on\\nsupported session lifecycle requests.\\n\\nAgents that also support `session/list` may return\\n`SessionInfo.additionalDirectories` to report the complete ordered\\nadditional-root list associated with a listed session.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionAdditionalDirectoriesCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"close\": {"] +#[doc = " \"description\": \"Whether the agent supports `session/close`.\\n\\nOptional. Omitted or `null` both mean the agent does not advertise support.\\nSupplying `{}` means the agent supports closing sessions.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionCloseCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"delete\": {"] +#[doc = " \"description\": \"Whether the agent supports `session/delete`.\\n\\nOptional. Omitted or `null` both mean the agent does not advertise support.\\nSupplying `{}` means the agent supports deleting sessions from `session/list`.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionDeleteCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"list\": {"] +#[doc = " \"description\": \"Whether the agent supports `session/list`.\\n\\nOptional. Omitted or `null` both mean the agent does not advertise support.\\nSupplying `{}` means the agent supports listing sessions.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionListCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"resume\": {"] +#[doc = " \"description\": \"Whether the agent supports `session/resume`.\\n\\nOptional. Omitted or `null` both mean the agent does not advertise support.\\nSupplying `{}` means the agent supports resuming sessions.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionResumeCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionCapabilities { + #[doc = "Whether the agent supports `additionalDirectories` on supported session lifecycle requests.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports `additionalDirectories` on\nsupported session lifecycle requests.\n\nAgents that also support `session/list` may return\n`SessionInfo.additionalDirectories` to report the complete ordered\nadditional-root list associated with a listed session."] + #[serde( + rename = "additionalDirectories", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub additional_directories: ::std::option::Option, + #[doc = "Whether the agent supports `session/close`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports closing sessions."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub close: ::std::option::Option, + #[doc = "Whether the agent supports `session/delete`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports deleting sessions from `session/list`."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub delete: ::std::option::Option, + #[doc = "Whether the agent supports `session/list`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports listing sessions."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub list: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Whether the agent supports `session/resume`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports resuming sessions."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub resume: ::std::option::Option, +} +impl ::std::default::Default for SessionCapabilities { + fn default() -> Self { + Self { + additional_directories: Default::default(), + close: Default::default(), + delete: Default::default(), + list: Default::default(), + meta: Default::default(), + resume: Default::default(), + } + } +} +impl SessionCapabilities { + pub fn builder() -> builder::SessionCapabilities { + Default::default() + } +} +#[doc = "Capabilities for the `session/close` method.\n\nSupplying `{}` means the agent supports closing sessions."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities for the `session/close` method.\\n\\nSupplying `{}` means the agent supports closing sessions.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionCloseCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SessionCloseCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl SessionCloseCapabilities { + pub fn builder() -> builder::SessionCloseCapabilities { + Default::default() + } +} +#[doc = "A boolean on/off toggle session configuration option payload."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A boolean on/off toggle session configuration option payload.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"currentValue\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"currentValue\": {"] +#[doc = " \"description\": \"The current value of the boolean option.\","] +#[doc = " \"type\": \"boolean\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigBoolean { + #[doc = "The current value of the boolean option."] + #[serde(rename = "currentValue")] + pub current_value: bool, +} +impl SessionConfigBoolean { + pub fn builder() -> builder::SessionConfigBoolean { + Default::default() + } +} +#[doc = "Unique identifier for a session configuration option value group."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a session configuration option value group.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct SessionConfigGroupId(pub ::std::string::String); +impl ::std::ops::Deref for SessionConfigGroupId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: SessionConfigGroupId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for SessionConfigGroupId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for SessionConfigGroupId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for SessionConfigGroupId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Unique identifier for a session configuration option."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a session configuration option.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct SessionConfigId(pub ::std::string::String); +impl ::std::ops::Deref for SessionConfigId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: SessionConfigId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for SessionConfigId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for SessionConfigId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for SessionConfigId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "A session configuration option selector and its current state."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A session configuration option selector and its current state.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"Single-value selector (dropdown).\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigSelect\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"select\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Boolean on/off toggle.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigBoolean\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"boolean\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"name\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"category\": {"] +#[doc = " \"description\": \"Optional semantic category for this option (UX only).\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOptionCategory\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"description\": {"] +#[doc = " \"description\": \"Optional description for the Client to display to the user.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"Unique identifier for the configuration option.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable label for the option.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"discriminator\": {"] +#[doc = " \"propertyName\": \"type\""] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum SessionConfigOption { + Variant0 { + #[doc = "Optional semantic category for this option (UX only)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + category: ::std::option::Option, + #[doc = "The currently selected value."] + #[serde(rename = "currentValue")] + current_value: SessionConfigValueId, + #[doc = "Optional description for the Client to display to the user."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + description: ::std::option::Option<::std::string::String>, + #[doc = "Unique identifier for the configuration option."] + id: SessionConfigId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable label for the option."] + name: ::std::string::String, + #[doc = "The set of selectable options."] + options: SessionConfigSelectOptions, + #[serde(rename = "type")] + type_: ::std::string::String, + }, + Variant1 { + #[doc = "Optional semantic category for this option (UX only)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + category: ::std::option::Option, + #[doc = "The current value of the boolean option."] + #[serde(rename = "currentValue")] + current_value: bool, + #[doc = "Optional description for the Client to display to the user."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + description: ::std::option::Option<::std::string::String>, + #[doc = "Unique identifier for the configuration option."] + id: SessionConfigId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable label for the option."] + name: ::std::string::String, + #[serde(rename = "type")] + type_: ::std::string::String, + }, +} +#[doc = "Semantic category for a session configuration option.\n\nThis is intended to help Clients distinguish broadly common selectors (e.g. model selector vs\nsession mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,\nplacement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown\ncategories gracefully.\n\nCategory names beginning with `_` are free for custom use, like other ACP extension methods.\nCategory names that do not begin with `_` are reserved for the ACP spec."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Semantic category for a session configuration option.\\n\\nThis is intended to help Clients distinguish broadly common selectors (e.g. model selector vs\\nsession mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,\\nplacement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown\\ncategories gracefully.\\n\\nCategory names beginning with `_` are free for custom use, like other ACP extension methods.\\nCategory names that do not begin with `_` are reserved for the ACP spec.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"Session mode selector.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"mode\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Model selector.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"model\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Model-related configuration parameter.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"model_config\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Thought/reasoning level selector.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"thought_level\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"other\","] +#[doc = " \"description\": \"Unknown / uncategorized selector.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigOptionCategory { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option<::std::string::String>, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option<::std::string::String>, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_2: ::std::option::Option<::std::string::String>, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_3: ::std::option::Option<::std::string::String>, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_4: ::std::option::Option<::std::string::String>, +} +impl ::std::default::Default for SessionConfigOptionCategory { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + subtype_2: Default::default(), + subtype_3: Default::default(), + subtype_4: Default::default(), + } + } +} +impl SessionConfigOptionCategory { + pub fn builder() -> builder::SessionConfigOptionCategory { + Default::default() + } +} +#[doc = "Session configuration option capabilities supported by the client."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Session configuration option capabilities supported by the client.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"boolean\": {"] +#[doc = " \"description\": \"Whether the client supports boolean session configuration options.\\n\\nOptional. Omitted or `null` both mean the client does not advertise support.\\nSupplying `{}` means agents may include `type: \\\"boolean\\\"` entries in\\n`configOptions`, and the client may send `session/set_config_option`\\nrequests with `type: \\\"boolean\\\"` and a boolean `value`.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/BooleanConfigOptionCapabilities\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigOptionsCapabilities { + #[doc = "Whether the client supports boolean session configuration options.\n\nOptional. Omitted or `null` both mean the client does not advertise support.\nSupplying `{}` means agents may include `type: \"boolean\"` entries in\n`configOptions`, and the client may send `session/set_config_option`\nrequests with `type: \"boolean\"` and a boolean `value`."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub boolean: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SessionConfigOptionsCapabilities { + fn default() -> Self { + Self { + boolean: Default::default(), + meta: Default::default(), + } + } +} +impl SessionConfigOptionsCapabilities { + pub fn builder() -> builder::SessionConfigOptionsCapabilities { + Default::default() + } +} +#[doc = "A single-value selector (dropdown) session configuration option payload."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A single-value selector (dropdown) session configuration option payload.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"currentValue\","] +#[doc = " \"options\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"currentValue\": {"] +#[doc = " \"description\": \"The currently selected value.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigValueId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"options\": {"] +#[doc = " \"description\": \"The set of selectable options.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigSelectOptions\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigSelect { + #[doc = "The currently selected value."] + #[serde(rename = "currentValue")] + pub current_value: SessionConfigValueId, + #[doc = "The set of selectable options."] + pub options: SessionConfigSelectOptions, +} +impl SessionConfigSelect { + pub fn builder() -> builder::SessionConfigSelect { + Default::default() + } +} +#[doc = "A group of possible values for a session configuration option."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A group of possible values for a session configuration option.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"group\","] +#[doc = " \"name\","] +#[doc = " \"options\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"group\": {"] +#[doc = " \"description\": \"Unique identifier for this group.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigGroupId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable label for this group.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"options\": {"] +#[doc = " \"description\": \"The set of option values in this group.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigSelectOption\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigSelectGroup { + #[doc = "Unique identifier for this group."] + pub group: SessionConfigGroupId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable label for this group."] + pub name: ::std::string::String, + #[doc = "The set of option values in this group."] + pub options: ::std::vec::Vec, +} +impl SessionConfigSelectGroup { + pub fn builder() -> builder::SessionConfigSelectGroup { + Default::default() + } +} +#[doc = "A possible value for a session configuration option."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A possible value for a session configuration option.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"name\","] +#[doc = " \"value\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"description\": {"] +#[doc = " \"description\": \"Optional description for this option value.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable label for this option value.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"value\": {"] +#[doc = " \"description\": \"Unique identifier for this option value.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigValueId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigSelectOption { + #[doc = "Optional description for this option value."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub description: ::std::option::Option<::std::string::String>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable label for this option value."] + pub name: ::std::string::String, + #[doc = "Unique identifier for this option value."] + pub value: SessionConfigValueId, +} +impl SessionConfigSelectOption { + pub fn builder() -> builder::SessionConfigSelectOption { + Default::default() + } +} +#[doc = "Possible values for a session configuration option."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Possible values for a session configuration option.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"title\": \"Ungrouped\","] +#[doc = " \"description\": \"A flat list of options with no grouping.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigSelectOption\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"Grouped\","] +#[doc = " \"description\": \"A list of options grouped under headers.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigSelectGroup\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionConfigSelectOptions { + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_0: ::std::option::Option<::std::vec::Vec>, + #[serde( + flatten, + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub subtype_1: ::std::option::Option<::std::vec::Vec>, +} +impl ::std::default::Default for SessionConfigSelectOptions { + fn default() -> Self { + Self { + subtype_0: Default::default(), + subtype_1: Default::default(), + } + } +} +impl SessionConfigSelectOptions { + pub fn builder() -> builder::SessionConfigSelectOptions { + Default::default() + } +} +#[doc = "Unique identifier for a session configuration option value."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a session configuration option value.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct SessionConfigValueId(pub ::std::string::String); +impl ::std::ops::Deref for SessionConfigValueId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: SessionConfigValueId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for SessionConfigValueId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for SessionConfigValueId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for SessionConfigValueId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Capabilities for the `session/delete` method.\n\nSupplying `{}` means the agent supports deleting sessions from `session/list`."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities for the `session/delete` method.\\n\\nSupplying `{}` means the agent supports deleting sessions from `session/list`.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionDeleteCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SessionDeleteCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl SessionDeleteCapabilities { + pub fn builder() -> builder::SessionDeleteCapabilities { + Default::default() + } +} +#[doc = "A unique identifier for a conversation session between a client and agent.\n\nSessions maintain their own context, conversation history, and state,\nallowing multiple independent interactions with the same agent.\n\nSee protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A unique identifier for a conversation session between a client and agent.\\n\\nSessions maintain their own context, conversation history, and state,\\nallowing multiple independent interactions with the same agent.\\n\\nSee protocol docs: [Session ID](https://agentclientprotocol.com/protocol/session-setup#session-id)\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct SessionId(pub ::std::string::String); +impl ::std::ops::Deref for SessionId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: SessionId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for SessionId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for SessionId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for SessionId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Information about a session returned by session/list"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Information about a session returned by session/list\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"cwd\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"additionalDirectories\": {"] +#[doc = " \"description\": \"Additional workspace roots reported for this session. Each path must be absolute.\\n\\nWhen present, this is the complete ordered additional-root list reported\\nby the Agent. Omitted and empty values are equivalent: the response\\nreports no additional roots.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"cwd\": {"] +#[doc = " \"description\": \"The working directory for this session. Must be an absolute path.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"Unique identifier for the session\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"title\": {"] +#[doc = " \"description\": \"Human-readable title for the session\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"updatedAt\": {"] +#[doc = " \"description\": \"ISO 8601 timestamp of last activity\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionInfo { + #[doc = "Additional workspace roots reported for this session. Each path must be absolute.\n\nWhen present, this is the complete ordered additional-root list reported\nby the Agent. Omitted and empty values are equivalent: the response\nreports no additional roots."] + #[serde( + rename = "additionalDirectories", + default, + skip_serializing_if = "::std::vec::Vec::is_empty" + )] + pub additional_directories: ::std::vec::Vec<::std::string::String>, + #[doc = "The working directory for this session. Must be an absolute path."] + pub cwd: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Unique identifier for the session"] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "Human-readable title for the session"] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub title: ::std::option::Option<::std::string::String>, + #[doc = "ISO 8601 timestamp of last activity"] + #[serde( + rename = "updatedAt", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub updated_at: ::std::option::Option<::std::string::String>, +} +impl SessionInfo { + pub fn builder() -> builder::SessionInfo { + Default::default() + } +} +#[doc = "Update to session metadata. All fields are optional to support partial updates.\n\nAgents send this notification to update session information like title or custom metadata.\nThis allows clients to display dynamic session names and track session state changes."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Update to session metadata. All fields are optional to support partial updates.\\n\\nAgents send this notification to update session information like title or custom metadata.\\nThis allows clients to display dynamic session names and track session state changes.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"title\": {"] +#[doc = " \"description\": \"Human-readable title for the session. Set to null to clear.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"updatedAt\": {"] +#[doc = " \"description\": \"ISO 8601 timestamp of last activity. Set to null to clear.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionInfoUpdate { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable title for the session. Set to null to clear."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub title: ::std::option::Option<::std::string::String>, + #[doc = "ISO 8601 timestamp of last activity. Set to null to clear."] + #[serde( + rename = "updatedAt", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub updated_at: ::std::option::Option<::std::string::String>, +} +impl ::std::default::Default for SessionInfoUpdate { + fn default() -> Self { + Self { + meta: Default::default(), + title: Default::default(), + updated_at: Default::default(), + } + } +} +impl SessionInfoUpdate { + pub fn builder() -> builder::SessionInfoUpdate { + Default::default() + } +} +#[doc = "Capabilities for the `session/list` method.\n\nSupplying `{}` means the agent supports listing sessions."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities for the `session/list` method.\\n\\nSupplying `{}` means the agent supports listing sessions.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionListCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SessionListCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl SessionListCapabilities { + pub fn builder() -> builder::SessionListCapabilities { + Default::default() + } +} +#[doc = "A mode the agent can operate in.\n\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A mode the agent can operate in.\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"id\","] +#[doc = " \"name\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"description\": {"] +#[doc = " \"description\": \"Optional human-readable details shown with this protocol object.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"id\": {"] +#[doc = " \"description\": \"Stable identifier used to refer to this protocol object in later messages.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"name\": {"] +#[doc = " \"description\": \"Human-readable name shown for this protocol object.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionMode { + #[doc = "Optional human-readable details shown with this protocol object."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub description: ::std::option::Option<::std::string::String>, + #[doc = "Stable identifier used to refer to this protocol object in later messages."] + pub id: SessionModeId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Human-readable name shown for this protocol object."] + pub name: ::std::string::String, +} +impl SessionMode { + pub fn builder() -> builder::SessionMode { + Default::default() + } +} +#[doc = "Unique identifier for a Session Mode."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a Session Mode.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct SessionModeId(pub ::std::string::String); +impl ::std::ops::Deref for SessionModeId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: SessionModeId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for SessionModeId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for SessionModeId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for SessionModeId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "The set of modes and the one currently active."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"The set of modes and the one currently active.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"availableModes\","] +#[doc = " \"currentModeId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"availableModes\": {"] +#[doc = " \"description\": \"The set of modes that the Agent can operate in\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionMode\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"currentModeId\": {"] +#[doc = " \"description\": \"The current mode the Agent is in.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionModeState { + #[doc = "The set of modes that the Agent can operate in"] + #[serde(rename = "availableModes")] + pub available_modes: ::std::vec::Vec, + #[doc = "The current mode the Agent is in."] + #[serde(rename = "currentModeId")] + pub current_mode_id: SessionModeId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl SessionModeState { + pub fn builder() -> builder::SessionModeState { + Default::default() + } +} +#[doc = "Notification containing a session update from the agent.\n\nUsed to stream real-time progress and results during prompt processing.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Notification containing a session update from the agent.\\n\\nUsed to stream real-time progress and results during prompt processing.\\n\\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\","] +#[doc = " \"update\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session this update pertains to.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"update\": {"] +#[doc = " \"description\": \"The actual update content.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionUpdate\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/update\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionNotification { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session this update pertains to."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "The actual update content."] + pub update: SessionUpdate, +} +impl SessionNotification { + pub fn builder() -> builder::SessionNotification { + Default::default() + } +} +#[doc = "Capabilities for the `session/resume` method.\n\nSupplying `{}` means the agent supports resuming sessions."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Capabilities for the `session/resume` method.\\n\\nSupplying `{}` means the agent supports resuming sessions.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SessionResumeCapabilities { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SessionResumeCapabilities { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl SessionResumeCapabilities { + pub fn builder() -> builder::SessionResumeCapabilities { + Default::default() + } +} +#[doc = "Different types of updates that can be sent during session processing.\n\nThese updates provide real-time feedback about the agent's progress.\n\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Different types of updates that can be sent during session processing.\\n\\nThese updates provide real-time feedback about the agent's progress.\\n\\nSee protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"A chunk of the user's message being streamed.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ContentChunk\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"user_message_chunk\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"A chunk of the agent's response being streamed.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ContentChunk\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"agent_message_chunk\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"A chunk of the agent's internal reasoning being streamed.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ContentChunk\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"agent_thought_chunk\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Notification that a new tool call has been initiated.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCall\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"tool_call\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Update on the status or results of a tool call.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallUpdate\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"tool_call_update\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The agent's execution plan for complex tasks.\\nSee protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Plan\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"plan\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Available commands are ready or have changed\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/AvailableCommandsUpdate\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"available_commands_update\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The current mode of the session has changed\\n\\nSee protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/CurrentModeUpdate\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"current_mode_update\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Session configuration options have been updated.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ConfigOptionUpdate\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"config_option_update\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Session metadata has been updated (title, timestamps, custom metadata)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionInfoUpdate\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"session_info_update\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Context window and cost update for the session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/UsageUpdate\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"sessionUpdate\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"sessionUpdate\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"usage_update\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"discriminator\": {"] +#[doc = " \"propertyName\": \"sessionUpdate\""] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum SessionUpdate { + Variant0 { + #[doc = "A single item of content"] + content: ContentBlock, + #[doc = "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started."] + #[serde( + rename = "messageId", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + message_id: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant1 { + #[doc = "A single item of content"] + content: ContentBlock, + #[doc = "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started."] + #[serde( + rename = "messageId", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + message_id: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant2 { + #[doc = "A single item of content"] + content: ContentBlock, + #[doc = "A unique identifier for the message this chunk belongs to.\n\nAll chunks belonging to the same message share the same `messageId`.\nA change in `messageId` indicates a new message has started."] + #[serde( + rename = "messageId", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + message_id: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant3 { + #[doc = "Content produced by the tool call."] + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + content: ::std::vec::Vec, + #[doc = "The category of tool being invoked.\nHelps clients choose appropriate icons and UI treatment."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + kind: ::std::option::Option, + #[doc = "File locations affected by this tool call.\nEnables \"follow-along\" features in clients."] + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + locations: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Raw input parameters sent to the tool."] + #[serde( + rename = "rawInput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + raw_input: ::std::option::Option<::serde_json::Value>, + #[doc = "Raw output returned by the tool."] + #[serde( + rename = "rawOutput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + raw_output: ::std::option::Option<::serde_json::Value>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + #[doc = "Current execution status of the tool call."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + status: ::std::option::Option, + #[doc = "Human-readable title describing what the tool is doing."] + title: ::std::string::String, + #[doc = "Unique identifier for this tool call within the session."] + #[serde(rename = "toolCallId")] + tool_call_id: ToolCallId, + }, + Variant4 { + #[doc = "Replace the content collection."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + content: ::std::option::Option<::std::vec::Vec>, + #[doc = "Update the tool kind."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + kind: ::std::option::Option, + #[doc = "Replace the locations collection."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + locations: ::std::option::Option<::std::vec::Vec>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Update the raw input."] + #[serde( + rename = "rawInput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + raw_input: ::std::option::Option<::serde_json::Value>, + #[doc = "Update the raw output."] + #[serde( + rename = "rawOutput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + raw_output: ::std::option::Option<::serde_json::Value>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + #[doc = "Update the execution status."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + status: ::std::option::Option, + #[doc = "Update the human-readable title."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + title: ::std::option::Option<::std::string::String>, + #[doc = "The ID of the tool call being updated."] + #[serde(rename = "toolCallId")] + tool_call_id: ToolCallId, + }, + Variant5 { + #[doc = "The list of tasks to be accomplished.\n\nWhen updating a plan, the agent must send a complete list of all entries\nwith their current status. The client replaces the entire plan with each update."] + entries: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant6 { + #[doc = "Commands the agent can execute"] + #[serde(rename = "availableCommands")] + available_commands: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant7 { + #[doc = "The ID of the current mode"] + #[serde(rename = "currentModeId")] + current_mode_id: SessionModeId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant8 { + #[doc = "The full set of configuration options and their current values."] + #[serde(rename = "configOptions")] + config_options: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + }, + Variant9 { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + #[doc = "Human-readable title for the session. Set to null to clear."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + title: ::std::option::Option<::std::string::String>, + #[doc = "ISO 8601 timestamp of last activity. Set to null to clear."] + #[serde( + rename = "updatedAt", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + updated_at: ::std::option::Option<::std::string::String>, + }, + Variant10 { + #[doc = "Cumulative session cost (optional)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + cost: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "sessionUpdate")] + session_update: ::std::string::String, + #[doc = "Total context window size in tokens."] + size: u64, + #[doc = "Tokens currently in context."] + used: u64, + }, +} +#[doc = "Request parameters for setting a session configuration option."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for setting a session configuration option.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"A boolean value (`type: \\\"boolean\\\"`).\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"type\","] +#[doc = " \"value\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"boolean\""] +#[doc = " },"] +#[doc = " \"value\": {"] +#[doc = " \"description\": \"The boolean value.\","] +#[doc = " \"type\": \"boolean\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"title\": \"value_id\","] +#[doc = " \"description\": \"A [`SessionConfigValueId`] string value.\\n\\nThis is the default when `type` is absent on the wire. Unknown `type`\\nvalues with string payloads also gracefully deserialize into this\\nvariant.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"value\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"value\": {"] +#[doc = " \"description\": \"The value ID.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigValueId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"configId\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configId\": {"] +#[doc = " \"description\": \"The ID of the configuration option to set.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to set the configuration option for.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/set_config_option\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum SetSessionConfigOptionRequest { + Variant0 { + #[doc = "The ID of the configuration option to set."] + #[serde(rename = "configId")] + config_id: SessionConfigId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to set the configuration option for."] + #[serde(rename = "sessionId")] + session_id: SessionId, + #[serde(rename = "type")] + type_: ::std::string::String, + #[doc = "The boolean value."] + value: bool, + }, + Variant1 { + #[doc = "The ID of the configuration option to set."] + #[serde(rename = "configId")] + config_id: SessionConfigId, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the session to set the configuration option for."] + #[serde(rename = "sessionId")] + session_id: SessionId, + #[doc = "The value ID."] + value: SessionConfigValueId, + }, +} +#[doc = "Response to `session/set_config_option` method."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to `session/set_config_option` method.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"configOptions\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"configOptions\": {"] +#[doc = " \"description\": \"The full set of configuration options and their current values.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/SessionConfigOption\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/set_config_option\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SetSessionConfigOptionResponse { + #[doc = "The full set of configuration options and their current values."] + #[serde(rename = "configOptions")] + pub config_options: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl SetSessionConfigOptionResponse { + pub fn builder() -> builder::SetSessionConfigOptionResponse { + Default::default() + } +} +#[doc = "Request parameters for setting a session mode."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request parameters for setting a session mode.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"modeId\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"modeId\": {"] +#[doc = " \"description\": \"The ID of the mode to set.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionModeId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The ID of the session to set the mode for.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/set_mode\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SetSessionModeRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The ID of the mode to set."] + #[serde(rename = "modeId")] + pub mode_id: SessionModeId, + #[doc = "The ID of the session to set the mode for."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl SetSessionModeRequest { + pub fn builder() -> builder::SetSessionModeRequest { + Default::default() + } +} +#[doc = "Response to `session/set_mode` method."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to `session/set_mode` method.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"session/set_mode\","] +#[doc = " \"x-side\": \"agent\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct SetSessionModeResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for SetSessionModeResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl SetSessionModeResponse { + pub fn builder() -> builder::SetSessionModeResponse { + Default::default() + } +} +#[doc = "Reasons why an agent stops processing a prompt turn.\n\nSee protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Reasons why an agent stops processing a prompt turn.\\n\\nSee protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"The turn ended successfully.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"end_turn\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The turn ended because the agent reached the maximum number of tokens.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"max_tokens\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The turn ended because the agent reached the maximum number of allowed\\nagent requests between user turns.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"max_turn_requests\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The turn ended because the agent refused to continue. The user prompt\\nand everything that comes after it won't be included in the next\\nprompt, so this should be reflected in the UI.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"refusal\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The turn was cancelled by the client via `session/cancel`.\\n\\nThis stop reason MUST be returned when the client sends a `session/cancel`\\nnotification, even if the cancellation causes exceptions in underlying operations.\\nAgents should catch these exceptions and return this semantically meaningful\\nresponse to confirm successful cancellation.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"cancelled\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum StopReason { + #[doc = "The turn ended successfully."] + #[serde(rename = "end_turn")] + EndTurn, + #[doc = "The turn ended because the agent reached the maximum number of tokens."] + #[serde(rename = "max_tokens")] + MaxTokens, + #[doc = "The turn ended because the agent reached the maximum number of allowed\nagent requests between user turns."] + #[serde(rename = "max_turn_requests")] + MaxTurnRequests, + #[doc = "The turn ended because the agent refused to continue. The user prompt\nand everything that comes after it won't be included in the next\nprompt, so this should be reflected in the UI."] + #[serde(rename = "refusal")] + Refusal, + #[doc = "The turn was cancelled by the client via `session/cancel`.\n\nThis stop reason MUST be returned when the client sends a `session/cancel`\nnotification, even if the cancellation causes exceptions in underlying operations.\nAgents should catch these exceptions and return this semantically meaningful\nresponse to confirm successful cancellation."] + #[serde(rename = "cancelled")] + Cancelled, +} +impl ::std::fmt::Display for StopReason { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::EndTurn => f.write_str("end_turn"), + Self::MaxTokens => f.write_str("max_tokens"), + Self::MaxTurnRequests => f.write_str("max_turn_requests"), + Self::Refusal => f.write_str("refusal"), + Self::Cancelled => f.write_str("cancelled"), + } + } +} +impl ::std::str::FromStr for StopReason { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "end_turn" => Ok(Self::EndTurn), + "max_tokens" => Ok(Self::MaxTokens), + "max_turn_requests" => Ok(Self::MaxTurnRequests), + "refusal" => Ok(Self::Refusal), + "cancelled" => Ok(Self::Cancelled), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for StopReason { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for StopReason { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for StopReason { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "Embed a terminal created with `terminal/create` by its id.\n\nThe terminal must be added before calling `terminal/release`.\n\nSee protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Embed a terminal created with `terminal/create` by its id.\\n\\nThe terminal must be added before calling `terminal/release`.\\n\\nSee protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"terminalId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"terminalId\": {"] +#[doc = " \"description\": \"Identifier of the terminal instance to embed in the content stream.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct Terminal { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Identifier of the terminal instance to embed in the content stream."] + #[serde(rename = "terminalId")] + pub terminal_id: TerminalId, +} +impl Terminal { + pub fn builder() -> builder::Terminal { + Default::default() + } +} +#[doc = "Exit status of a terminal command."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Exit status of a terminal command.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"exitCode\": {"] +#[doc = " \"description\": \"The process exit code (may be null if terminated by signal).\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"uint32\","] +#[doc = " \"minimum\": 0.0,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"signal\": {"] +#[doc = " \"description\": \"The signal that terminated the process (may be null if exited normally).\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct TerminalExitStatus { + #[doc = "The process exit code (may be null if terminated by signal)."] + #[serde( + rename = "exitCode", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub exit_code: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The signal that terminated the process (may be null if exited normally)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub signal: ::std::option::Option<::std::string::String>, +} +impl ::std::default::Default for TerminalExitStatus { + fn default() -> Self { + Self { + exit_code: Default::default(), + meta: Default::default(), + signal: Default::default(), + } + } +} +impl TerminalExitStatus { + pub fn builder() -> builder::TerminalExitStatus { + Default::default() + } +} +#[doc = "Typed identifier used for terminal values on the wire."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Typed identifier used for terminal values on the wire.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct TerminalId(pub ::std::string::String); +impl ::std::ops::Deref for TerminalId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: TerminalId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for TerminalId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for TerminalId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for TerminalId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "Request to get the current output and status of a terminal."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to get the current output and status of a terminal.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\","] +#[doc = " \"terminalId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"terminalId\": {"] +#[doc = " \"description\": \"The ID of the terminal to get output from.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/output\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct TerminalOutputRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "The ID of the terminal to get output from."] + #[serde(rename = "terminalId")] + pub terminal_id: TerminalId, +} +impl TerminalOutputRequest { + pub fn builder() -> builder::TerminalOutputRequest { + Default::default() + } +} +#[doc = "Response containing the terminal output and exit status."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response containing the terminal output and exit status.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"output\","] +#[doc = " \"truncated\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"exitStatus\": {"] +#[doc = " \"description\": \"Exit status if the command has completed.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalExitStatus\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"output\": {"] +#[doc = " \"description\": \"The terminal output captured so far.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"truncated\": {"] +#[doc = " \"description\": \"Whether the output was truncated due to byte limits.\","] +#[doc = " \"type\": \"boolean\""] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/output\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct TerminalOutputResponse { + #[doc = "Exit status if the command has completed."] + #[serde( + rename = "exitStatus", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub exit_status: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The terminal output captured so far."] + pub output: ::std::string::String, + #[doc = "Whether the output was truncated due to byte limits."] + pub truncated: bool, +} +impl TerminalOutputResponse { + pub fn builder() -> builder::TerminalOutputResponse { + Default::default() + } +} +#[doc = "Text provided to or from an LLM."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Text provided to or from an LLM.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"text\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"annotations\": {"] +#[doc = " \"description\": \"Optional annotations that help clients decide how to display or route this content.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Annotations\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"text\": {"] +#[doc = " \"description\": \"Text payload carried by this content block.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct TextContent { + #[doc = "Optional annotations that help clients decide how to display or route this content."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub annotations: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Text payload carried by this content block."] + pub text: ::std::string::String, +} +impl TextContent { + pub fn builder() -> builder::TextContent { + Default::default() + } +} +#[doc = "Text-based resource contents."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Text-based resource contents.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"text\","] +#[doc = " \"uri\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"mimeType\": {"] +#[doc = " \"description\": \"MIME type describing the encoded media payload.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"text\": {"] +#[doc = " \"description\": \"Text payload carried by this content block.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"uri\": {"] +#[doc = " \"description\": \"URI associated with this resource or media payload.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct TextResourceContents { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "MIME type describing the encoded media payload."] + #[serde( + rename = "mimeType", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub mime_type: ::std::option::Option<::std::string::String>, + #[doc = "Text payload carried by this content block."] + pub text: ::std::string::String, + #[doc = "URI associated with this resource or media payload."] + pub uri: ::std::string::String, +} +impl TextResourceContents { + pub fn builder() -> builder::TextResourceContents { + Default::default() + } +} +#[doc = "Represents a tool call that the language model has requested.\n\nTool calls are actions that the agent executes on behalf of the language model,\nsuch as reading files, executing code, or fetching data from external sources.\n\nSee protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Represents a tool call that the language model has requested.\\n\\nTool calls are actions that the agent executes on behalf of the language model,\\nsuch as reading files, executing code, or fetching data from external sources.\\n\\nSee protocol docs: [Tool Calls](https://agentclientprotocol.com/protocol/tool-calls)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"title\","] +#[doc = " \"toolCallId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"Content produced by the tool call.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallContent\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"kind\": {"] +#[doc = " \"description\": \"The category of tool being invoked.\\nHelps clients choose appropriate icons and UI treatment.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolKind\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"locations\": {"] +#[doc = " \"description\": \"File locations affected by this tool call.\\nEnables \\\"follow-along\\\" features in clients.\","] +#[doc = " \"type\": \"array\","] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallLocation\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"rawInput\": {"] +#[doc = " \"description\": \"Raw input parameters sent to the tool.\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"rawOutput\": {"] +#[doc = " \"description\": \"Raw output returned by the tool.\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"status\": {"] +#[doc = " \"description\": \"Current execution status of the tool call.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallStatus\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"title\": {"] +#[doc = " \"description\": \"Human-readable title describing what the tool is doing.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"toolCallId\": {"] +#[doc = " \"description\": \"Unique identifier for this tool call within the session.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ToolCall { + #[doc = "Content produced by the tool call."] + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub content: ::std::vec::Vec, + #[doc = "The category of tool being invoked.\nHelps clients choose appropriate icons and UI treatment."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub kind: ::std::option::Option, + #[doc = "File locations affected by this tool call.\nEnables \"follow-along\" features in clients."] + #[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")] + pub locations: ::std::vec::Vec, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Raw input parameters sent to the tool."] + #[serde( + rename = "rawInput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub raw_input: ::std::option::Option<::serde_json::Value>, + #[doc = "Raw output returned by the tool."] + #[serde( + rename = "rawOutput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub raw_output: ::std::option::Option<::serde_json::Value>, + #[doc = "Current execution status of the tool call."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub status: ::std::option::Option, + #[doc = "Human-readable title describing what the tool is doing."] + pub title: ::std::string::String, + #[doc = "Unique identifier for this tool call within the session."] + #[serde(rename = "toolCallId")] + pub tool_call_id: ToolCallId, +} +impl ToolCall { + pub fn builder() -> builder::ToolCall { + Default::default() + } +} +#[doc = "Content produced by a tool call.\n\nTool calls can produce different types of content including\nstandard content blocks (text, images) or file diffs.\n\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Content produced by a tool call.\\n\\nTool calls can produce different types of content including\\nstandard content blocks (text, images) or file diffs.\\n\\nSee protocol docs: [Content](https://agentclientprotocol.com/protocol/tool-calls#content)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"Standard content block (text, images, resources).\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Content\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"content\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"File modification shown as a diff.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Diff\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"diff\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Embed a terminal created with `terminal/create` by its id.\\n\\nThe terminal must be added before calling `terminal/release`.\\n\\nSee protocol docs: [Terminal](https://agentclientprotocol.com/protocol/terminals)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Terminal\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"required\": ["] +#[doc = " \"type\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"type\": {"] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"terminal\""] +#[doc = " }"] +#[doc = " }"] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"discriminator\": {"] +#[doc = " \"propertyName\": \"type\""] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +#[serde(untagged)] +pub enum ToolCallContent { + Variant0 { + #[doc = "The actual content block."] + content: ContentBlock, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[serde(rename = "type")] + type_: ::std::string::String, + }, + Variant1 { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The new content after modification."] + #[serde(rename = "newText")] + new_text: ::std::string::String, + #[doc = "The original content (None for new files)."] + #[serde( + rename = "oldText", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + old_text: ::std::option::Option<::std::string::String>, + #[doc = "The absolute file path being modified."] + path: ::std::string::String, + #[serde(rename = "type")] + type_: ::std::string::String, + }, + Variant2 { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Identifier of the terminal instance to embed in the content stream."] + #[serde(rename = "terminalId")] + terminal_id: TerminalId, + #[serde(rename = "type")] + type_: ::std::string::String, + }, +} +#[doc = "Unique identifier for a tool call within a session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Unique identifier for a tool call within a session.\","] +#[doc = " \"type\": \"string\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +#[serde(transparent)] +pub struct ToolCallId(pub ::std::string::String); +impl ::std::ops::Deref for ToolCallId { + type Target = ::std::string::String; + fn deref(&self) -> &::std::string::String { + &self.0 + } +} +impl ::std::convert::From for ::std::string::String { + fn from(value: ToolCallId) -> Self { + value.0 + } +} +impl ::std::convert::From<::std::string::String> for ToolCallId { + fn from(value: ::std::string::String) -> Self { + Self(value) + } +} +impl ::std::str::FromStr for ToolCallId { + type Err = ::std::convert::Infallible; + fn from_str(value: &str) -> ::std::result::Result { + Ok(Self(value.to_string())) + } +} +impl ::std::fmt::Display for ToolCallId { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + self.0.fmt(f) + } +} +#[doc = "A file location being accessed or modified by a tool.\n\nEnables clients to implement \"follow-along\" features that track\nwhich files the agent is working with in real-time.\n\nSee protocol docs: [Following the Agent](https://agentclientprotocol.com/protocol/tool-calls#following-the-agent)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"A file location being accessed or modified by a tool.\\n\\nEnables clients to implement \\\"follow-along\\\" features that track\\nwhich files the agent is working with in real-time.\\n\\nSee protocol docs: [Following the Agent](https://agentclientprotocol.com/protocol/tool-calls#following-the-agent)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"path\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"line\": {"] +#[doc = " \"description\": \"Optional line number within the file.\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"uint32\","] +#[doc = " \"minimum\": 0.0,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"path\": {"] +#[doc = " \"description\": \"The absolute file path being accessed or modified.\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ToolCallLocation { + #[doc = "Optional line number within the file."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub line: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The absolute file path being accessed or modified."] + pub path: ::std::string::String, +} +impl ToolCallLocation { + pub fn builder() -> builder::ToolCallLocation { + Default::default() + } +} +#[doc = "Execution status of a tool call.\n\nTool calls progress through different statuses during their lifecycle.\n\nSee protocol docs: [Status](https://agentclientprotocol.com/protocol/tool-calls#status)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Execution status of a tool call.\\n\\nTool calls progress through different statuses during their lifecycle.\\n\\nSee protocol docs: [Status](https://agentclientprotocol.com/protocol/tool-calls#status)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"The tool call hasn't started running yet because the input is either\\nstreaming or we're awaiting approval.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"pending\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The tool call is currently running.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"in_progress\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The tool call completed successfully.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"completed\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"The tool call failed with an error.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"failed\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum ToolCallStatus { + #[doc = "The tool call hasn't started running yet because the input is either\nstreaming or we're awaiting approval."] + #[serde(rename = "pending")] + Pending, + #[doc = "The tool call is currently running."] + #[serde(rename = "in_progress")] + InProgress, + #[doc = "The tool call completed successfully."] + #[serde(rename = "completed")] + Completed, + #[doc = "The tool call failed with an error."] + #[serde(rename = "failed")] + Failed, +} +impl ::std::fmt::Display for ToolCallStatus { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::Pending => f.write_str("pending"), + Self::InProgress => f.write_str("in_progress"), + Self::Completed => f.write_str("completed"), + Self::Failed => f.write_str("failed"), + } + } +} +impl ::std::str::FromStr for ToolCallStatus { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "pending" => Ok(Self::Pending), + "in_progress" => Ok(Self::InProgress), + "completed" => Ok(Self::Completed), + "failed" => Ok(Self::Failed), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for ToolCallStatus { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for ToolCallStatus { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for ToolCallStatus { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "An update to an existing tool call.\n\nUsed to report progress and results as tools execute. All fields except\nthe tool call ID are optional - only changed fields need to be included.\n\nSee protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"An update to an existing tool call.\\n\\nUsed to report progress and results as tools execute. All fields except\\nthe tool call ID are optional - only changed fields need to be included.\\n\\nSee protocol docs: [Updating](https://agentclientprotocol.com/protocol/tool-calls#updating)\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"toolCallId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"Replace the content collection.\","] +#[doc = " \"type\": ["] +#[doc = " \"array\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallContent\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"kind\": {"] +#[doc = " \"description\": \"Update the tool kind.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolKind\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"locations\": {"] +#[doc = " \"description\": \"Replace the locations collection.\","] +#[doc = " \"type\": ["] +#[doc = " \"array\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"items\": {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallLocation\""] +#[doc = " },"] +#[doc = " \"x-deserialize-default-on-error\": true,"] +#[doc = " \"x-deserialize-skip-invalid-items\": true"] +#[doc = " },"] +#[doc = " \"rawInput\": {"] +#[doc = " \"description\": \"Update the raw input.\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"rawOutput\": {"] +#[doc = " \"description\": \"Update the raw output.\","] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"status\": {"] +#[doc = " \"description\": \"Update the execution status.\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallStatus\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"title\": {"] +#[doc = " \"description\": \"Update the human-readable title.\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"toolCallId\": {"] +#[doc = " \"description\": \"The ID of the tool call being updated.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/ToolCallId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct ToolCallUpdate { + #[doc = "Replace the content collection."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub content: ::std::option::Option<::std::vec::Vec>, + #[doc = "Update the tool kind."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub kind: ::std::option::Option, + #[doc = "Replace the locations collection."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub locations: ::std::option::Option<::std::vec::Vec>, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Update the raw input."] + #[serde( + rename = "rawInput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub raw_input: ::std::option::Option<::serde_json::Value>, + #[doc = "Update the raw output."] + #[serde( + rename = "rawOutput", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub raw_output: ::std::option::Option<::serde_json::Value>, + #[doc = "Update the execution status."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub status: ::std::option::Option, + #[doc = "Update the human-readable title."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub title: ::std::option::Option<::std::string::String>, + #[doc = "The ID of the tool call being updated."] + #[serde(rename = "toolCallId")] + pub tool_call_id: ToolCallId, +} +impl ToolCallUpdate { + pub fn builder() -> builder::ToolCallUpdate { + Default::default() + } +} +#[doc = "Categories of tools that can be invoked.\n\nTool kinds help clients choose appropriate icons and optimize how they\ndisplay tool execution progress.\n\nSee protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating)"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Categories of tools that can be invoked.\\n\\nTool kinds help clients choose appropriate icons and optimize how they\\ndisplay tool execution progress.\\n\\nSee protocol docs: [Creating](https://agentclientprotocol.com/protocol/tool-calls#creating)\","] +#[doc = " \"oneOf\": ["] +#[doc = " {"] +#[doc = " \"description\": \"Reading files or data.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"read\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Modifying files or content.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"edit\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Removing files or data.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"delete\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Moving or renaming files.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"move\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Searching for information.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"search\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Running commands or code.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"execute\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Internal reasoning or planning.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"think\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Retrieving external data.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"fetch\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Switching the current session mode.\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"switch_mode\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"description\": \"Other tool types (default).\","] +#[doc = " \"type\": \"string\","] +#[doc = " \"const\": \"other\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive( + :: serde :: Deserialize, + :: serde :: Serialize, + Clone, + Copy, + Debug, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, +)] +pub enum ToolKind { + #[doc = "Reading files or data."] + #[serde(rename = "read")] + Read, + #[doc = "Modifying files or content."] + #[serde(rename = "edit")] + Edit, + #[doc = "Removing files or data."] + #[serde(rename = "delete")] + Delete, + #[doc = "Moving or renaming files."] + #[serde(rename = "move")] + Move, + #[doc = "Searching for information."] + #[serde(rename = "search")] + Search, + #[doc = "Running commands or code."] + #[serde(rename = "execute")] + Execute, + #[doc = "Internal reasoning or planning."] + #[serde(rename = "think")] + Think, + #[doc = "Retrieving external data."] + #[serde(rename = "fetch")] + Fetch, + #[doc = "Switching the current session mode."] + #[serde(rename = "switch_mode")] + SwitchMode, + #[doc = "Other tool types (default)."] + #[serde(rename = "other")] + Other, +} +impl ::std::fmt::Display for ToolKind { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match *self { + Self::Read => f.write_str("read"), + Self::Edit => f.write_str("edit"), + Self::Delete => f.write_str("delete"), + Self::Move => f.write_str("move"), + Self::Search => f.write_str("search"), + Self::Execute => f.write_str("execute"), + Self::Think => f.write_str("think"), + Self::Fetch => f.write_str("fetch"), + Self::SwitchMode => f.write_str("switch_mode"), + Self::Other => f.write_str("other"), + } + } +} +impl ::std::str::FromStr for ToolKind { + type Err = self::error::ConversionError; + fn from_str(value: &str) -> ::std::result::Result { + match value { + "read" => Ok(Self::Read), + "edit" => Ok(Self::Edit), + "delete" => Ok(Self::Delete), + "move" => Ok(Self::Move), + "search" => Ok(Self::Search), + "execute" => Ok(Self::Execute), + "think" => Ok(Self::Think), + "fetch" => Ok(Self::Fetch), + "switch_mode" => Ok(Self::SwitchMode), + "other" => Ok(Self::Other), + _ => Err("invalid value".into()), + } + } +} +impl ::std::convert::TryFrom<&str> for ToolKind { + type Error = self::error::ConversionError; + fn try_from(value: &str) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<&::std::string::String> for ToolKind { + type Error = self::error::ConversionError; + fn try_from( + value: &::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +impl ::std::convert::TryFrom<::std::string::String> for ToolKind { + type Error = self::error::ConversionError; + fn try_from( + value: ::std::string::String, + ) -> ::std::result::Result { + value.parse() + } +} +#[doc = "All text that was typed after the command name is provided as input."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"All text that was typed after the command name is provided as input.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"hint\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"hint\": {"] +#[doc = " \"description\": \"A hint to display when the input hasn't been provided yet\","] +#[doc = " \"type\": \"string\""] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct UnstructuredCommandInput { + #[doc = "A hint to display when the input hasn't been provided yet"] + pub hint: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl UnstructuredCommandInput { + pub fn builder() -> builder::UnstructuredCommandInput { + Default::default() + } +} +#[doc = "Context window and cost update for a session."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Context window and cost update for a session.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"size\","] +#[doc = " \"used\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"cost\": {"] +#[doc = " \"description\": \"Cumulative session cost (optional).\","] +#[doc = " \"anyOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/Cost\""] +#[doc = " },"] +#[doc = " {"] +#[doc = " \"type\": \"null\""] +#[doc = " }"] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"size\": {"] +#[doc = " \"description\": \"Total context window size in tokens.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"uint64\","] +#[doc = " \"minimum\": 0.0"] +#[doc = " },"] +#[doc = " \"used\": {"] +#[doc = " \"description\": \"Tokens currently in context.\","] +#[doc = " \"type\": \"integer\","] +#[doc = " \"format\": \"uint64\","] +#[doc = " \"minimum\": 0.0"] +#[doc = " }"] +#[doc = " }"] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct UsageUpdate { + #[doc = "Cumulative session cost (optional)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub cost: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Total context window size in tokens."] + pub size: u64, + #[doc = "Tokens currently in context."] + pub used: u64, +} +impl UsageUpdate { + pub fn builder() -> builder::UsageUpdate { + Default::default() + } +} +#[doc = "Request to wait for a terminal command to exit."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to wait for a terminal command to exit.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"sessionId\","] +#[doc = " \"terminalId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " },"] +#[doc = " \"terminalId\": {"] +#[doc = " \"description\": \"The ID of the terminal to wait for.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/TerminalId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/wait_for_exit\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct WaitForTerminalExitRequest { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, + #[doc = "The ID of the terminal to wait for."] + #[serde(rename = "terminalId")] + pub terminal_id: TerminalId, +} +impl WaitForTerminalExitRequest { + pub fn builder() -> builder::WaitForTerminalExitRequest { + Default::default() + } +} +#[doc = "Response containing the exit status of a terminal command."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response containing the exit status of a terminal command.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"exitCode\": {"] +#[doc = " \"description\": \"The process exit code (may be null if terminated by signal).\","] +#[doc = " \"type\": ["] +#[doc = " \"integer\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"format\": \"uint32\","] +#[doc = " \"minimum\": 0.0,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"signal\": {"] +#[doc = " \"description\": \"The signal that terminated the process (may be null if exited normally).\","] +#[doc = " \"type\": ["] +#[doc = " \"string\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"terminal/wait_for_exit\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct WaitForTerminalExitResponse { + #[doc = "The process exit code (may be null if terminated by signal)."] + #[serde( + rename = "exitCode", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub exit_code: ::std::option::Option, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "The signal that terminated the process (may be null if exited normally)."] + #[serde(default, skip_serializing_if = "::std::option::Option::is_none")] + pub signal: ::std::option::Option<::std::string::String>, +} +impl ::std::default::Default for WaitForTerminalExitResponse { + fn default() -> Self { + Self { + exit_code: Default::default(), + meta: Default::default(), + signal: Default::default(), + } + } +} +impl WaitForTerminalExitResponse { + pub fn builder() -> builder::WaitForTerminalExitResponse { + Default::default() + } +} +#[doc = "Request to write content to a text file.\n\nOnly available if the client supports the `fs.writeTextFile` capability."] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Request to write content to a text file.\\n\\nOnly available if the client supports the `fs.writeTextFile` capability.\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"required\": ["] +#[doc = " \"content\","] +#[doc = " \"path\","] +#[doc = " \"sessionId\""] +#[doc = " ],"] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " },"] +#[doc = " \"content\": {"] +#[doc = " \"description\": \"The text content to write to the file.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"path\": {"] +#[doc = " \"description\": \"Absolute path to the file to write.\","] +#[doc = " \"type\": \"string\""] +#[doc = " },"] +#[doc = " \"sessionId\": {"] +#[doc = " \"description\": \"The session ID for this request.\","] +#[doc = " \"allOf\": ["] +#[doc = " {"] +#[doc = " \"$ref\": \"#/$defs/SessionId\""] +#[doc = " }"] +#[doc = " ]"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"fs/write_text_file\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct WriteTextFileRequest { + #[doc = "The text content to write to the file."] + pub content: ::std::string::String, + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + #[doc = "Absolute path to the file to write."] + pub path: ::std::string::String, + #[doc = "The session ID for this request."] + #[serde(rename = "sessionId")] + pub session_id: SessionId, +} +impl WriteTextFileRequest { + pub fn builder() -> builder::WriteTextFileRequest { + Default::default() + } +} +#[doc = "Response to `fs/write_text_file`"] +#[doc = r""] +#[doc = r"
JSON schema"] +#[doc = r""] +#[doc = r" ```json"] +#[doc = "{"] +#[doc = " \"description\": \"Response to `fs/write_text_file`\","] +#[doc = " \"type\": \"object\","] +#[doc = " \"properties\": {"] +#[doc = " \"_meta\": {"] +#[doc = " \"description\": \"The _meta property is reserved by ACP to allow clients and agents to attach additional\\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\\nthese keys.\\n\\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)\","] +#[doc = " \"type\": ["] +#[doc = " \"object\","] +#[doc = " \"null\""] +#[doc = " ],"] +#[doc = " \"additionalProperties\": true,"] +#[doc = " \"x-deserialize-default-on-error\": true"] +#[doc = " }"] +#[doc = " },"] +#[doc = " \"x-method\": \"fs/write_text_file\","] +#[doc = " \"x-side\": \"client\""] +#[doc = "}"] +#[doc = r" ```"] +#[doc = r"
"] +#[derive(:: serde :: Deserialize, :: serde :: Serialize, Clone, Debug)] +pub struct WriteTextFileResponse { + #[doc = "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)"] + #[serde( + rename = "_meta", + default, + skip_serializing_if = "::std::option::Option::is_none" + )] + pub meta: ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, +} +impl ::std::default::Default for WriteTextFileResponse { + fn default() -> Self { + Self { + meta: Default::default(), + } + } +} +impl WriteTextFileResponse { + pub fn builder() -> builder::WriteTextFileResponse { + Default::default() + } +} +#[doc = r" Types for composing complex structures."] +pub mod builder { + #[derive(Clone, Debug)] + pub struct AgentAuthCapabilities { + logout: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for AgentAuthCapabilities { + fn default() -> Self { + Self { + logout: Ok(Default::default()), + meta: Ok(Default::default()), + } + } + } + impl AgentAuthCapabilities { + pub fn logout(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.logout = value + .try_into() + .map_err(|e| format!("error converting supplied value for logout: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentAuthCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: AgentAuthCapabilities, + ) -> ::std::result::Result { + Ok(Self { + logout: value.logout?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for AgentAuthCapabilities { + fn from(value: super::AgentAuthCapabilities) -> Self { + Self { + logout: Ok(value.logout), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentCapabilities { + auth: ::std::result::Result, + load_session: ::std::result::Result, + mcp_capabilities: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + prompt_capabilities: + ::std::result::Result, + session_capabilities: + ::std::result::Result, + } + impl ::std::default::Default for AgentCapabilities { + fn default() -> Self { + Self { + auth: Ok(super::defaults::agent_capabilities_auth()), + load_session: Ok(Default::default()), + mcp_capabilities: Ok(super::defaults::agent_capabilities_mcp_capabilities()), + meta: Ok(Default::default()), + prompt_capabilities: Ok(super::defaults::agent_capabilities_prompt_capabilities()), + session_capabilities: Ok(super::defaults::agent_capabilities_session_capabilities()), + } + } + } + impl AgentCapabilities { + pub fn auth(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.auth = value + .try_into() + .map_err(|e| format!("error converting supplied value for auth: {e}")); + self + } + pub fn load_session(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.load_session = value + .try_into() + .map_err(|e| format!("error converting supplied value for load_session: {e}")); + self + } + pub fn mcp_capabilities(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.mcp_capabilities = value + .try_into() + .map_err(|e| format!("error converting supplied value for mcp_capabilities: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn prompt_capabilities(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.prompt_capabilities = value.try_into().map_err(|e| { + format!("error converting supplied value for prompt_capabilities: {e}") + }); + self + } + pub fn session_capabilities(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_capabilities = value.try_into().map_err(|e| { + format!("error converting supplied value for session_capabilities: {e}") + }); + self + } + } + impl ::std::convert::TryFrom for super::AgentCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: AgentCapabilities, + ) -> ::std::result::Result { + Ok(Self { + auth: value.auth?, + load_session: value.load_session?, + mcp_capabilities: value.mcp_capabilities?, + meta: value.meta?, + prompt_capabilities: value.prompt_capabilities?, + session_capabilities: value.session_capabilities?, + }) + } + } + impl ::std::convert::From for AgentCapabilities { + fn from(value: super::AgentCapabilities) -> Self { + Self { + auth: Ok(value.auth), + load_session: Ok(value.load_session), + mcp_capabilities: Ok(value.mcp_capabilities), + meta: Ok(value.meta), + prompt_capabilities: Ok(value.prompt_capabilities), + session_capabilities: Ok(value.session_capabilities), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentClientProtocol { + subtype_0: + ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_1: + ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for AgentClientProtocol { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + } + } + } + impl AgentClientProtocol { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentClientProtocol { + type Error = super::error::ConversionError; + fn try_from( + value: AgentClientProtocol, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + }) + } + } + impl ::std::convert::From for AgentClientProtocol { + fn from(value: super::AgentClientProtocol) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentNotification { + method: ::std::result::Result<::std::string::String, ::std::string::String>, + params: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for AgentNotification { + fn default() -> Self { + Self { + method: Err("no value supplied for method".to_string()), + params: Ok(Default::default()), + } + } + } + impl AgentNotification { + pub fn method(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.method = value + .try_into() + .map_err(|e| format!("error converting supplied value for method: {e}")); + self + } + pub fn params(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.params = value + .try_into() + .map_err(|e| format!("error converting supplied value for params: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentNotification { + type Error = super::error::ConversionError; + fn try_from( + value: AgentNotification, + ) -> ::std::result::Result { + Ok(Self { + method: value.method?, + params: value.params?, + }) + } + } + impl ::std::convert::From for AgentNotification { + fn from(value: super::AgentNotification) -> Self { + Self { + method: Ok(value.method), + params: Ok(value.params), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentNotificationParams { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for AgentNotificationParams { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + } + } + } + impl AgentNotificationParams { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentNotificationParams { + type Error = super::error::ConversionError; + fn try_from( + value: AgentNotificationParams, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + }) + } + } + impl ::std::convert::From for AgentNotificationParams { + fn from(value: super::AgentNotificationParams) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentRequest { + id: ::std::result::Result, + method: ::std::result::Result<::std::string::String, ::std::string::String>, + params: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for AgentRequest { + fn default() -> Self { + Self { + id: Err("no value supplied for id".to_string()), + method: Err("no value supplied for method".to_string()), + params: Ok(Default::default()), + } + } + } + impl AgentRequest { + pub fn id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {e}")); + self + } + pub fn method(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.method = value + .try_into() + .map_err(|e| format!("error converting supplied value for method: {e}")); + self + } + pub fn params(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.params = value + .try_into() + .map_err(|e| format!("error converting supplied value for params: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentRequest { + type Error = super::error::ConversionError; + fn try_from( + value: AgentRequest, + ) -> ::std::result::Result { + Ok(Self { + id: value.id?, + method: value.method?, + params: value.params?, + }) + } + } + impl ::std::convert::From for AgentRequest { + fn from(value: super::AgentRequest) -> Self { + Self { + id: Ok(value.id), + method: Ok(value.method), + params: Ok(value.params), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentRequestParams { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_3: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_4: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_5: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_6: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_7: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_8: + ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for AgentRequestParams { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + subtype_5: Ok(Default::default()), + subtype_6: Ok(Default::default()), + subtype_7: Ok(Default::default()), + subtype_8: Ok(Default::default()), + } + } + } + impl AgentRequestParams { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + pub fn subtype_5(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_5 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_5: {e}")); + self + } + pub fn subtype_6(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_6 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_6: {e}")); + self + } + pub fn subtype_7(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_7 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_7: {e}")); + self + } + pub fn subtype_8(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_8 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_8: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentRequestParams { + type Error = super::error::ConversionError; + fn try_from( + value: AgentRequestParams, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + subtype_5: value.subtype_5?, + subtype_6: value.subtype_6?, + subtype_7: value.subtype_7?, + subtype_8: value.subtype_8?, + }) + } + } + impl ::std::convert::From for AgentRequestParams { + fn from(value: super::AgentRequestParams) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + subtype_5: Ok(value.subtype_5), + subtype_6: Ok(value.subtype_6), + subtype_7: Ok(value.subtype_7), + subtype_8: Ok(value.subtype_8), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentVariant0Params { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_3: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_4: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_5: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_6: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_7: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_8: + ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for AgentVariant0Params { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + subtype_5: Ok(Default::default()), + subtype_6: Ok(Default::default()), + subtype_7: Ok(Default::default()), + subtype_8: Ok(Default::default()), + } + } + } + impl AgentVariant0Params { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + pub fn subtype_5(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_5 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_5: {e}")); + self + } + pub fn subtype_6(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_6 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_6: {e}")); + self + } + pub fn subtype_7(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_7 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_7: {e}")); + self + } + pub fn subtype_8(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_8 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_8: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentVariant0Params { + type Error = super::error::ConversionError; + fn try_from( + value: AgentVariant0Params, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + subtype_5: value.subtype_5?, + subtype_6: value.subtype_6?, + subtype_7: value.subtype_7?, + subtype_8: value.subtype_8?, + }) + } + } + impl ::std::convert::From for AgentVariant0Params { + fn from(value: super::AgentVariant0Params) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + subtype_5: Ok(value.subtype_5), + subtype_6: Ok(value.subtype_6), + subtype_7: Ok(value.subtype_7), + subtype_8: Ok(value.subtype_8), + } + } + } + #[derive(Clone, Debug)] + pub struct AgentVariant2Params { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for AgentVariant2Params { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + } + } + } + impl AgentVariant2Params { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AgentVariant2Params { + type Error = super::error::ConversionError; + fn try_from( + value: AgentVariant2Params, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + }) + } + } + impl ::std::convert::From for AgentVariant2Params { + fn from(value: super::AgentVariant2Params) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + } + } + } + #[derive(Clone, Debug)] + pub struct Annotations { + audience: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + last_modified: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + priority: ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for Annotations { + fn default() -> Self { + Self { + audience: Ok(Default::default()), + last_modified: Ok(Default::default()), + meta: Ok(Default::default()), + priority: Ok(Default::default()), + } + } + } + impl Annotations { + pub fn audience(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::vec::Vec>>, + T::Error: ::std::fmt::Display, + { + self.audience = value + .try_into() + .map_err(|e| format!("error converting supplied value for audience: {e}")); + self + } + pub fn last_modified(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.last_modified = value + .try_into() + .map_err(|e| format!("error converting supplied value for last_modified: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn priority(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.priority = value + .try_into() + .map_err(|e| format!("error converting supplied value for priority: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Annotations { + type Error = super::error::ConversionError; + fn try_from( + value: Annotations, + ) -> ::std::result::Result { + Ok(Self { + audience: value.audience?, + last_modified: value.last_modified?, + meta: value.meta?, + priority: value.priority?, + }) + } + } + impl ::std::convert::From for Annotations { + fn from(value: super::Annotations) -> Self { + Self { + audience: Ok(value.audience), + last_modified: Ok(value.last_modified), + meta: Ok(value.meta), + priority: Ok(value.priority), + } + } + } + #[derive(Clone, Debug)] + pub struct AudioContent { + annotations: + ::std::result::Result<::std::option::Option, ::std::string::String>, + data: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + mime_type: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for AudioContent { + fn default() -> Self { + Self { + annotations: Ok(Default::default()), + data: Err("no value supplied for data".to_string()), + meta: Ok(Default::default()), + mime_type: Err("no value supplied for mime_type".to_string()), + } + } + } + impl AudioContent { + pub fn annotations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.annotations = value + .try_into() + .map_err(|e| format!("error converting supplied value for annotations: {e}")); + self + } + pub fn data(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.data = value + .try_into() + .map_err(|e| format!("error converting supplied value for data: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn mime_type(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.mime_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for mime_type: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AudioContent { + type Error = super::error::ConversionError; + fn try_from( + value: AudioContent, + ) -> ::std::result::Result { + Ok(Self { + annotations: value.annotations?, + data: value.data?, + meta: value.meta?, + mime_type: value.mime_type?, + }) + } + } + impl ::std::convert::From for AudioContent { + fn from(value: super::AudioContent) -> Self { + Self { + annotations: Ok(value.annotations), + data: Ok(value.data), + meta: Ok(value.meta), + mime_type: Ok(value.mime_type), + } + } + } + #[derive(Clone, Debug)] + pub struct AuthMethodAgent { + description: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + id: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for AuthMethodAgent { + fn default() -> Self { + Self { + description: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + } + } + } + impl AuthMethodAgent { + pub fn description(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.description = value + .try_into() + .map_err(|e| format!("error converting supplied value for description: {e}")); + self + } + pub fn id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AuthMethodAgent { + type Error = super::error::ConversionError; + fn try_from( + value: AuthMethodAgent, + ) -> ::std::result::Result { + Ok(Self { + description: value.description?, + id: value.id?, + meta: value.meta?, + name: value.name?, + }) + } + } + impl ::std::convert::From for AuthMethodAgent { + fn from(value: super::AuthMethodAgent) -> Self { + Self { + description: Ok(value.description), + id: Ok(value.id), + meta: Ok(value.meta), + name: Ok(value.name), + } + } + } + #[derive(Clone, Debug)] + pub struct AuthenticateRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + method_id: ::std::result::Result, + } + impl ::std::default::Default for AuthenticateRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + method_id: Err("no value supplied for method_id".to_string()), + } + } + } + impl AuthenticateRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn method_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.method_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for method_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AuthenticateRequest { + type Error = super::error::ConversionError; + fn try_from( + value: AuthenticateRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + method_id: value.method_id?, + }) + } + } + impl ::std::convert::From for AuthenticateRequest { + fn from(value: super::AuthenticateRequest) -> Self { + Self { + meta: Ok(value.meta), + method_id: Ok(value.method_id), + } + } + } + #[derive(Clone, Debug)] + pub struct AuthenticateResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for AuthenticateResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl AuthenticateResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AuthenticateResponse { + type Error = super::error::ConversionError; + fn try_from( + value: AuthenticateResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for AuthenticateResponse { + fn from(value: super::AuthenticateResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct AvailableCommand { + description: ::std::result::Result<::std::string::String, ::std::string::String>, + input: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for AvailableCommand { + fn default() -> Self { + Self { + description: Err("no value supplied for description".to_string()), + input: Ok(Default::default()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + } + } + } + impl AvailableCommand { + pub fn description(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.description = value + .try_into() + .map_err(|e| format!("error converting supplied value for description: {e}")); + self + } + pub fn input(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.input = value + .try_into() + .map_err(|e| format!("error converting supplied value for input: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AvailableCommand { + type Error = super::error::ConversionError; + fn try_from( + value: AvailableCommand, + ) -> ::std::result::Result { + Ok(Self { + description: value.description?, + input: value.input?, + meta: value.meta?, + name: value.name?, + }) + } + } + impl ::std::convert::From for AvailableCommand { + fn from(value: super::AvailableCommand) -> Self { + Self { + description: Ok(value.description), + input: Ok(value.input), + meta: Ok(value.meta), + name: Ok(value.name), + } + } + } + #[derive(Clone, Debug)] + pub struct AvailableCommandsUpdate { + available_commands: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for AvailableCommandsUpdate { + fn default() -> Self { + Self { + available_commands: Err("no value supplied for available_commands".to_string()), + meta: Ok(Default::default()), + } + } + } + impl AvailableCommandsUpdate { + pub fn available_commands(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.available_commands = value.try_into().map_err(|e| { + format!("error converting supplied value for available_commands: {e}") + }); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::AvailableCommandsUpdate { + type Error = super::error::ConversionError; + fn try_from( + value: AvailableCommandsUpdate, + ) -> ::std::result::Result { + Ok(Self { + available_commands: value.available_commands?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for AvailableCommandsUpdate { + fn from(value: super::AvailableCommandsUpdate) -> Self { + Self { + available_commands: Ok(value.available_commands), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct BlobResourceContents { + blob: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + mime_type: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + uri: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for BlobResourceContents { + fn default() -> Self { + Self { + blob: Err("no value supplied for blob".to_string()), + meta: Ok(Default::default()), + mime_type: Ok(Default::default()), + uri: Err("no value supplied for uri".to_string()), + } + } + } + impl BlobResourceContents { + pub fn blob(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.blob = value + .try_into() + .map_err(|e| format!("error converting supplied value for blob: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn mime_type(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.mime_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for mime_type: {e}")); + self + } + pub fn uri(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.uri = value + .try_into() + .map_err(|e| format!("error converting supplied value for uri: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::BlobResourceContents { + type Error = super::error::ConversionError; + fn try_from( + value: BlobResourceContents, + ) -> ::std::result::Result { + Ok(Self { + blob: value.blob?, + meta: value.meta?, + mime_type: value.mime_type?, + uri: value.uri?, + }) + } + } + impl ::std::convert::From for BlobResourceContents { + fn from(value: super::BlobResourceContents) -> Self { + Self { + blob: Ok(value.blob), + meta: Ok(value.meta), + mime_type: Ok(value.mime_type), + uri: Ok(value.uri), + } + } + } + #[derive(Clone, Debug)] + pub struct BooleanConfigOptionCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for BooleanConfigOptionCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl BooleanConfigOptionCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom + for super::BooleanConfigOptionCapabilities + { + type Error = super::error::ConversionError; + fn try_from( + value: BooleanConfigOptionCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From + for BooleanConfigOptionCapabilities + { + fn from(value: super::BooleanConfigOptionCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct CancelNotification { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + } + impl ::std::default::Default for CancelNotification { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl CancelNotification { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CancelNotification { + type Error = super::error::ConversionError; + fn try_from( + value: CancelNotification, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for CancelNotification { + fn from(value: super::CancelNotification) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct CancelRequestNotification { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + request_id: ::std::result::Result, + } + impl ::std::default::Default for CancelRequestNotification { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + request_id: Err("no value supplied for request_id".to_string()), + } + } + } + impl CancelRequestNotification { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn request_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.request_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for request_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CancelRequestNotification { + type Error = super::error::ConversionError; + fn try_from( + value: CancelRequestNotification, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + request_id: value.request_id?, + }) + } + } + impl ::std::convert::From for CancelRequestNotification { + fn from(value: super::CancelRequestNotification) -> Self { + Self { + meta: Ok(value.meta), + request_id: Ok(value.request_id), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientCapabilities { + fs: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + terminal: ::std::result::Result, + } + impl ::std::default::Default for ClientCapabilities { + fn default() -> Self { + Self { + fs: Ok(super::defaults::client_capabilities_fs()), + meta: Ok(Default::default()), + session: Ok(Default::default()), + terminal: Ok(Default::default()), + } + } + } + impl ClientCapabilities { + pub fn fs(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.fs = value + .try_into() + .map_err(|e| format!("error converting supplied value for fs: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.session = value + .try_into() + .map_err(|e| format!("error converting supplied value for session: {e}")); + self + } + pub fn terminal(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: ClientCapabilities, + ) -> ::std::result::Result { + Ok(Self { + fs: value.fs?, + meta: value.meta?, + session: value.session?, + terminal: value.terminal?, + }) + } + } + impl ::std::convert::From for ClientCapabilities { + fn from(value: super::ClientCapabilities) -> Self { + Self { + fs: Ok(value.fs), + meta: Ok(value.meta), + session: Ok(value.session), + terminal: Ok(value.terminal), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientNotification { + method: ::std::result::Result<::std::string::String, ::std::string::String>, + params: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for ClientNotification { + fn default() -> Self { + Self { + method: Err("no value supplied for method".to_string()), + params: Ok(Default::default()), + } + } + } + impl ClientNotification { + pub fn method(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.method = value + .try_into() + .map_err(|e| format!("error converting supplied value for method: {e}")); + self + } + pub fn params(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.params = value + .try_into() + .map_err(|e| format!("error converting supplied value for params: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientNotification { + type Error = super::error::ConversionError; + fn try_from( + value: ClientNotification, + ) -> ::std::result::Result { + Ok(Self { + method: value.method?, + params: value.params?, + }) + } + } + impl ::std::convert::From for ClientNotification { + fn from(value: super::ClientNotification) -> Self { + Self { + method: Ok(value.method), + params: Ok(value.params), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientNotificationParams { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for ClientNotificationParams { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + } + } + } + impl ClientNotificationParams { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientNotificationParams { + type Error = super::error::ConversionError; + fn try_from( + value: ClientNotificationParams, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + }) + } + } + impl ::std::convert::From for ClientNotificationParams { + fn from(value: super::ClientNotificationParams) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientRequest { + id: ::std::result::Result, + method: ::std::result::Result<::std::string::String, ::std::string::String>, + params: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for ClientRequest { + fn default() -> Self { + Self { + id: Err("no value supplied for id".to_string()), + method: Err("no value supplied for method".to_string()), + params: Ok(Default::default()), + } + } + } + impl ClientRequest { + pub fn id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {e}")); + self + } + pub fn method(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.method = value + .try_into() + .map_err(|e| format!("error converting supplied value for method: {e}")); + self + } + pub fn params(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.params = value + .try_into() + .map_err(|e| format!("error converting supplied value for params: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientRequest { + type Error = super::error::ConversionError; + fn try_from( + value: ClientRequest, + ) -> ::std::result::Result { + Ok(Self { + id: value.id?, + method: value.method?, + params: value.params?, + }) + } + } + impl ::std::convert::From for ClientRequest { + fn from(value: super::ClientRequest) -> Self { + Self { + id: Ok(value.id), + method: Ok(value.method), + params: Ok(value.params), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientRequestParams { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_3: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_4: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_5: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_6: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_7: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_8: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_9: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_10: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_11: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_12: + ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for ClientRequestParams { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + subtype_5: Ok(Default::default()), + subtype_6: Ok(Default::default()), + subtype_7: Ok(Default::default()), + subtype_8: Ok(Default::default()), + subtype_9: Ok(Default::default()), + subtype_10: Ok(Default::default()), + subtype_11: Ok(Default::default()), + subtype_12: Ok(Default::default()), + } + } + } + impl ClientRequestParams { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + pub fn subtype_5(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_5 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_5: {e}")); + self + } + pub fn subtype_6(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_6 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_6: {e}")); + self + } + pub fn subtype_7(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_7 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_7: {e}")); + self + } + pub fn subtype_8(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_8 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_8: {e}")); + self + } + pub fn subtype_9(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_9 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_9: {e}")); + self + } + pub fn subtype_10(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_10 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_10: {e}")); + self + } + pub fn subtype_11(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_11 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_11: {e}")); + self + } + pub fn subtype_12(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_12 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_12: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientRequestParams { + type Error = super::error::ConversionError; + fn try_from( + value: ClientRequestParams, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + subtype_5: value.subtype_5?, + subtype_6: value.subtype_6?, + subtype_7: value.subtype_7?, + subtype_8: value.subtype_8?, + subtype_9: value.subtype_9?, + subtype_10: value.subtype_10?, + subtype_11: value.subtype_11?, + subtype_12: value.subtype_12?, + }) + } + } + impl ::std::convert::From for ClientRequestParams { + fn from(value: super::ClientRequestParams) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + subtype_5: Ok(value.subtype_5), + subtype_6: Ok(value.subtype_6), + subtype_7: Ok(value.subtype_7), + subtype_8: Ok(value.subtype_8), + subtype_9: Ok(value.subtype_9), + subtype_10: Ok(value.subtype_10), + subtype_11: Ok(value.subtype_11), + subtype_12: Ok(value.subtype_12), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientSessionCapabilities { + config_options: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for ClientSessionCapabilities { + fn default() -> Self { + Self { + config_options: Ok(Default::default()), + meta: Ok(Default::default()), + } + } + } + impl ClientSessionCapabilities { + pub fn config_options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option, + >, + T::Error: ::std::fmt::Display, + { + self.config_options = value + .try_into() + .map_err(|e| format!("error converting supplied value for config_options: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientSessionCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: ClientSessionCapabilities, + ) -> ::std::result::Result { + Ok(Self { + config_options: value.config_options?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for ClientSessionCapabilities { + fn from(value: super::ClientSessionCapabilities) -> Self { + Self { + config_options: Ok(value.config_options), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientVariant0Params { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_3: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_4: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_5: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_6: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_7: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_8: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_9: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_10: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_11: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_12: + ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for ClientVariant0Params { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + subtype_5: Ok(Default::default()), + subtype_6: Ok(Default::default()), + subtype_7: Ok(Default::default()), + subtype_8: Ok(Default::default()), + subtype_9: Ok(Default::default()), + subtype_10: Ok(Default::default()), + subtype_11: Ok(Default::default()), + subtype_12: Ok(Default::default()), + } + } + } + impl ClientVariant0Params { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + pub fn subtype_5(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_5 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_5: {e}")); + self + } + pub fn subtype_6(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_6 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_6: {e}")); + self + } + pub fn subtype_7(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_7 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_7: {e}")); + self + } + pub fn subtype_8(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_8 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_8: {e}")); + self + } + pub fn subtype_9(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_9 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_9: {e}")); + self + } + pub fn subtype_10(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_10 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_10: {e}")); + self + } + pub fn subtype_11(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_11 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_11: {e}")); + self + } + pub fn subtype_12(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_12 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_12: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientVariant0Params { + type Error = super::error::ConversionError; + fn try_from( + value: ClientVariant0Params, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + subtype_5: value.subtype_5?, + subtype_6: value.subtype_6?, + subtype_7: value.subtype_7?, + subtype_8: value.subtype_8?, + subtype_9: value.subtype_9?, + subtype_10: value.subtype_10?, + subtype_11: value.subtype_11?, + subtype_12: value.subtype_12?, + }) + } + } + impl ::std::convert::From for ClientVariant0Params { + fn from(value: super::ClientVariant0Params) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + subtype_5: Ok(value.subtype_5), + subtype_6: Ok(value.subtype_6), + subtype_7: Ok(value.subtype_7), + subtype_8: Ok(value.subtype_8), + subtype_9: Ok(value.subtype_9), + subtype_10: Ok(value.subtype_10), + subtype_11: Ok(value.subtype_11), + subtype_12: Ok(value.subtype_12), + } + } + } + #[derive(Clone, Debug)] + pub struct ClientVariant2Params { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for ClientVariant2Params { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + } + } + } + impl ClientVariant2Params { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ClientVariant2Params { + type Error = super::error::ConversionError; + fn try_from( + value: ClientVariant2Params, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + }) + } + } + impl ::std::convert::From for ClientVariant2Params { + fn from(value: super::ClientVariant2Params) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + } + } + } + #[derive(Clone, Debug)] + pub struct CloseSessionRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + } + impl ::std::default::Default for CloseSessionRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl CloseSessionRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CloseSessionRequest { + type Error = super::error::ConversionError; + fn try_from( + value: CloseSessionRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for CloseSessionRequest { + fn from(value: super::CloseSessionRequest) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct CloseSessionResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for CloseSessionResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl CloseSessionResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CloseSessionResponse { + type Error = super::error::ConversionError; + fn try_from( + value: CloseSessionResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for CloseSessionResponse { + fn from(value: super::CloseSessionResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct ConfigOptionUpdate { + config_options: ::std::result::Result< + ::std::vec::Vec, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for ConfigOptionUpdate { + fn default() -> Self { + Self { + config_options: Err("no value supplied for config_options".to_string()), + meta: Ok(Default::default()), + } + } + } + impl ConfigOptionUpdate { + pub fn config_options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.config_options = value + .try_into() + .map_err(|e| format!("error converting supplied value for config_options: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ConfigOptionUpdate { + type Error = super::error::ConversionError; + fn try_from( + value: ConfigOptionUpdate, + ) -> ::std::result::Result { + Ok(Self { + config_options: value.config_options?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for ConfigOptionUpdate { + fn from(value: super::ConfigOptionUpdate) -> Self { + Self { + config_options: Ok(value.config_options), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct Content { + content: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for Content { + fn default() -> Self { + Self { + content: Err("no value supplied for content".to_string()), + meta: Ok(Default::default()), + } + } + } + impl Content { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Content { + type Error = super::error::ConversionError; + fn try_from(value: Content) -> ::std::result::Result { + Ok(Self { + content: value.content?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for Content { + fn from(value: super::Content) -> Self { + Self { + content: Ok(value.content), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct ContentChunk { + content: ::std::result::Result, + message_id: + ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for ContentChunk { + fn default() -> Self { + Self { + content: Err("no value supplied for content".to_string()), + message_id: Ok(Default::default()), + meta: Ok(Default::default()), + } + } + } + impl ContentChunk { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn message_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.message_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for message_id: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ContentChunk { + type Error = super::error::ConversionError; + fn try_from( + value: ContentChunk, + ) -> ::std::result::Result { + Ok(Self { + content: value.content?, + message_id: value.message_id?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for ContentChunk { + fn from(value: super::ContentChunk) -> Self { + Self { + content: Ok(value.content), + message_id: Ok(value.message_id), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct Cost { + amount: ::std::result::Result, + currency: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for Cost { + fn default() -> Self { + Self { + amount: Err("no value supplied for amount".to_string()), + currency: Err("no value supplied for currency".to_string()), + meta: Ok(Default::default()), + } + } + } + impl Cost { + pub fn amount(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.amount = value + .try_into() + .map_err(|e| format!("error converting supplied value for amount: {e}")); + self + } + pub fn currency(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.currency = value + .try_into() + .map_err(|e| format!("error converting supplied value for currency: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Cost { + type Error = super::error::ConversionError; + fn try_from(value: Cost) -> ::std::result::Result { + Ok(Self { + amount: value.amount?, + currency: value.currency?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for Cost { + fn from(value: super::Cost) -> Self { + Self { + amount: Ok(value.amount), + currency: Ok(value.currency), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct CreateTerminalRequest { + args: ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>, + command: ::std::result::Result<::std::string::String, ::std::string::String>, + cwd: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + env: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + output_byte_limit: ::std::result::Result<::std::option::Option, ::std::string::String>, + session_id: ::std::result::Result, + } + impl ::std::default::Default for CreateTerminalRequest { + fn default() -> Self { + Self { + args: Ok(Default::default()), + command: Err("no value supplied for command".to_string()), + cwd: Ok(Default::default()), + env: Ok(Default::default()), + meta: Ok(Default::default()), + output_byte_limit: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl CreateTerminalRequest { + pub fn args(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.args = value + .try_into() + .map_err(|e| format!("error converting supplied value for args: {e}")); + self + } + pub fn command(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.command = value + .try_into() + .map_err(|e| format!("error converting supplied value for command: {e}")); + self + } + pub fn cwd(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.cwd = value + .try_into() + .map_err(|e| format!("error converting supplied value for cwd: {e}")); + self + } + pub fn env(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.env = value + .try_into() + .map_err(|e| format!("error converting supplied value for env: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn output_byte_limit(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.output_byte_limit = value + .try_into() + .map_err(|e| format!("error converting supplied value for output_byte_limit: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CreateTerminalRequest { + type Error = super::error::ConversionError; + fn try_from( + value: CreateTerminalRequest, + ) -> ::std::result::Result { + Ok(Self { + args: value.args?, + command: value.command?, + cwd: value.cwd?, + env: value.env?, + meta: value.meta?, + output_byte_limit: value.output_byte_limit?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for CreateTerminalRequest { + fn from(value: super::CreateTerminalRequest) -> Self { + Self { + args: Ok(value.args), + command: Ok(value.command), + cwd: Ok(value.cwd), + env: Ok(value.env), + meta: Ok(value.meta), + output_byte_limit: Ok(value.output_byte_limit), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct CreateTerminalResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + terminal_id: ::std::result::Result, + } + impl ::std::default::Default for CreateTerminalResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + terminal_id: Err("no value supplied for terminal_id".to_string()), + } + } + } + impl CreateTerminalResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn terminal_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CreateTerminalResponse { + type Error = super::error::ConversionError; + fn try_from( + value: CreateTerminalResponse, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + terminal_id: value.terminal_id?, + }) + } + } + impl ::std::convert::From for CreateTerminalResponse { + fn from(value: super::CreateTerminalResponse) -> Self { + Self { + meta: Ok(value.meta), + terminal_id: Ok(value.terminal_id), + } + } + } + #[derive(Clone, Debug)] + pub struct CurrentModeUpdate { + current_mode_id: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for CurrentModeUpdate { + fn default() -> Self { + Self { + current_mode_id: Err("no value supplied for current_mode_id".to_string()), + meta: Ok(Default::default()), + } + } + } + impl CurrentModeUpdate { + pub fn current_mode_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.current_mode_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for current_mode_id: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::CurrentModeUpdate { + type Error = super::error::ConversionError; + fn try_from( + value: CurrentModeUpdate, + ) -> ::std::result::Result { + Ok(Self { + current_mode_id: value.current_mode_id?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for CurrentModeUpdate { + fn from(value: super::CurrentModeUpdate) -> Self { + Self { + current_mode_id: Ok(value.current_mode_id), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct DeleteSessionRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + } + impl ::std::default::Default for DeleteSessionRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl DeleteSessionRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::DeleteSessionRequest { + type Error = super::error::ConversionError; + fn try_from( + value: DeleteSessionRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for DeleteSessionRequest { + fn from(value: super::DeleteSessionRequest) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct DeleteSessionResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for DeleteSessionResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl DeleteSessionResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::DeleteSessionResponse { + type Error = super::error::ConversionError; + fn try_from( + value: DeleteSessionResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for DeleteSessionResponse { + fn from(value: super::DeleteSessionResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct Diff { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + new_text: ::std::result::Result<::std::string::String, ::std::string::String>, + old_text: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + path: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for Diff { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + new_text: Err("no value supplied for new_text".to_string()), + old_text: Ok(Default::default()), + path: Err("no value supplied for path".to_string()), + } + } + } + impl Diff { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn new_text(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.new_text = value + .try_into() + .map_err(|e| format!("error converting supplied value for new_text: {e}")); + self + } + pub fn old_text(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.old_text = value + .try_into() + .map_err(|e| format!("error converting supplied value for old_text: {e}")); + self + } + pub fn path(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.path = value + .try_into() + .map_err(|e| format!("error converting supplied value for path: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Diff { + type Error = super::error::ConversionError; + fn try_from(value: Diff) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + new_text: value.new_text?, + old_text: value.old_text?, + path: value.path?, + }) + } + } + impl ::std::convert::From for Diff { + fn from(value: super::Diff) -> Self { + Self { + meta: Ok(value.meta), + new_text: Ok(value.new_text), + old_text: Ok(value.old_text), + path: Ok(value.path), + } + } + } + #[derive(Clone, Debug)] + pub struct EmbeddedResource { + annotations: + ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + resource: ::std::result::Result, + } + impl ::std::default::Default for EmbeddedResource { + fn default() -> Self { + Self { + annotations: Ok(Default::default()), + meta: Ok(Default::default()), + resource: Err("no value supplied for resource".to_string()), + } + } + } + impl EmbeddedResource { + pub fn annotations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.annotations = value + .try_into() + .map_err(|e| format!("error converting supplied value for annotations: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn resource(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.resource = value + .try_into() + .map_err(|e| format!("error converting supplied value for resource: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::EmbeddedResource { + type Error = super::error::ConversionError; + fn try_from( + value: EmbeddedResource, + ) -> ::std::result::Result { + Ok(Self { + annotations: value.annotations?, + meta: value.meta?, + resource: value.resource?, + }) + } + } + impl ::std::convert::From for EmbeddedResource { + fn from(value: super::EmbeddedResource) -> Self { + Self { + annotations: Ok(value.annotations), + meta: Ok(value.meta), + resource: Ok(value.resource), + } + } + } + #[derive(Clone, Debug)] + pub struct EmbeddedResourceResource { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for EmbeddedResourceResource { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + } + } + } + impl EmbeddedResourceResource { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::EmbeddedResourceResource { + type Error = super::error::ConversionError; + fn try_from( + value: EmbeddedResourceResource, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + }) + } + } + impl ::std::convert::From for EmbeddedResourceResource { + fn from(value: super::EmbeddedResourceResource) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + } + } + } + #[derive(Clone, Debug)] + pub struct EnvVariable { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + value: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for EnvVariable { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + value: Err("no value supplied for value".to_string()), + } + } + } + impl EnvVariable { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.value = value + .try_into() + .map_err(|e| format!("error converting supplied value for value: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::EnvVariable { + type Error = super::error::ConversionError; + fn try_from( + value: EnvVariable, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + name: value.name?, + value: value.value?, + }) + } + } + impl ::std::convert::From for EnvVariable { + fn from(value: super::EnvVariable) -> Self { + Self { + meta: Ok(value.meta), + name: Ok(value.name), + value: Ok(value.value), + } + } + } + #[derive(Clone, Debug)] + pub struct Error { + code: ::std::result::Result, + data: ::std::result::Result< + ::std::option::Option<::serde_json::Value>, + ::std::string::String, + >, + message: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for Error { + fn default() -> Self { + Self { + code: Err("no value supplied for code".to_string()), + data: Ok(Default::default()), + message: Err("no value supplied for message".to_string()), + } + } + } + impl Error { + pub fn code(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.code = value + .try_into() + .map_err(|e| format!("error converting supplied value for code: {e}")); + self + } + pub fn data(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::serde_json::Value>>, + T::Error: ::std::fmt::Display, + { + self.data = value + .try_into() + .map_err(|e| format!("error converting supplied value for data: {e}")); + self + } + pub fn message(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.message = value + .try_into() + .map_err(|e| format!("error converting supplied value for message: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Error { + type Error = super::error::ConversionError; + fn try_from(value: Error) -> ::std::result::Result { + Ok(Self { + code: value.code?, + data: value.data?, + message: value.message?, + }) + } + } + impl ::std::convert::From for Error { + fn from(value: super::Error) -> Self { + Self { + code: Ok(value.code), + data: Ok(value.data), + message: Ok(value.message), + } + } + } + #[derive(Clone, Debug)] + pub struct ErrorCode { + subtype_0: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_1: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_2: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_3: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_4: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_5: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_6: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_7: ::std::result::Result<::std::option::Option, ::std::string::String>, + subtype_8: ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for ErrorCode { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + subtype_5: Ok(Default::default()), + subtype_6: Ok(Default::default()), + subtype_7: Ok(Default::default()), + subtype_8: Ok(Default::default()), + } + } + } + impl ErrorCode { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + pub fn subtype_5(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_5 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_5: {e}")); + self + } + pub fn subtype_6(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_6 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_6: {e}")); + self + } + pub fn subtype_7(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_7 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_7: {e}")); + self + } + pub fn subtype_8(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_8 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_8: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ErrorCode { + type Error = super::error::ConversionError; + fn try_from( + value: ErrorCode, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + subtype_5: value.subtype_5?, + subtype_6: value.subtype_6?, + subtype_7: value.subtype_7?, + subtype_8: value.subtype_8?, + }) + } + } + impl ::std::convert::From for ErrorCode { + fn from(value: super::ErrorCode) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + subtype_5: Ok(value.subtype_5), + subtype_6: Ok(value.subtype_6), + subtype_7: Ok(value.subtype_7), + subtype_8: Ok(value.subtype_8), + } + } + } + #[derive(Clone, Debug)] + pub struct FileSystemCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + read_text_file: ::std::result::Result, + write_text_file: ::std::result::Result, + } + impl ::std::default::Default for FileSystemCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + read_text_file: Ok(Default::default()), + write_text_file: Ok(Default::default()), + } + } + } + impl FileSystemCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn read_text_file(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.read_text_file = value + .try_into() + .map_err(|e| format!("error converting supplied value for read_text_file: {e}")); + self + } + pub fn write_text_file(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.write_text_file = value + .try_into() + .map_err(|e| format!("error converting supplied value for write_text_file: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::FileSystemCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: FileSystemCapabilities, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + read_text_file: value.read_text_file?, + write_text_file: value.write_text_file?, + }) + } + } + impl ::std::convert::From for FileSystemCapabilities { + fn from(value: super::FileSystemCapabilities) -> Self { + Self { + meta: Ok(value.meta), + read_text_file: Ok(value.read_text_file), + write_text_file: Ok(value.write_text_file), + } + } + } + #[derive(Clone, Debug)] + pub struct HttpHeader { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + value: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for HttpHeader { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + value: Err("no value supplied for value".to_string()), + } + } + } + impl HttpHeader { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.value = value + .try_into() + .map_err(|e| format!("error converting supplied value for value: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::HttpHeader { + type Error = super::error::ConversionError; + fn try_from( + value: HttpHeader, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + name: value.name?, + value: value.value?, + }) + } + } + impl ::std::convert::From for HttpHeader { + fn from(value: super::HttpHeader) -> Self { + Self { + meta: Ok(value.meta), + name: Ok(value.name), + value: Ok(value.value), + } + } + } + #[derive(Clone, Debug)] + pub struct ImageContent { + annotations: + ::std::result::Result<::std::option::Option, ::std::string::String>, + data: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + mime_type: ::std::result::Result<::std::string::String, ::std::string::String>, + uri: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for ImageContent { + fn default() -> Self { + Self { + annotations: Ok(Default::default()), + data: Err("no value supplied for data".to_string()), + meta: Ok(Default::default()), + mime_type: Err("no value supplied for mime_type".to_string()), + uri: Ok(Default::default()), + } + } + } + impl ImageContent { + pub fn annotations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.annotations = value + .try_into() + .map_err(|e| format!("error converting supplied value for annotations: {e}")); + self + } + pub fn data(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.data = value + .try_into() + .map_err(|e| format!("error converting supplied value for data: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn mime_type(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.mime_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for mime_type: {e}")); + self + } + pub fn uri(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.uri = value + .try_into() + .map_err(|e| format!("error converting supplied value for uri: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ImageContent { + type Error = super::error::ConversionError; + fn try_from( + value: ImageContent, + ) -> ::std::result::Result { + Ok(Self { + annotations: value.annotations?, + data: value.data?, + meta: value.meta?, + mime_type: value.mime_type?, + uri: value.uri?, + }) + } + } + impl ::std::convert::From for ImageContent { + fn from(value: super::ImageContent) -> Self { + Self { + annotations: Ok(value.annotations), + data: Ok(value.data), + meta: Ok(value.meta), + mime_type: Ok(value.mime_type), + uri: Ok(value.uri), + } + } + } + #[derive(Clone, Debug)] + pub struct Implementation { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + title: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + version: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for Implementation { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + title: Ok(Default::default()), + version: Err("no value supplied for version".to_string()), + } + } + } + impl Implementation { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn title(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.title = value + .try_into() + .map_err(|e| format!("error converting supplied value for title: {e}")); + self + } + pub fn version(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.version = value + .try_into() + .map_err(|e| format!("error converting supplied value for version: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Implementation { + type Error = super::error::ConversionError; + fn try_from( + value: Implementation, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + name: value.name?, + title: value.title?, + version: value.version?, + }) + } + } + impl ::std::convert::From for Implementation { + fn from(value: super::Implementation) -> Self { + Self { + meta: Ok(value.meta), + name: Ok(value.name), + title: Ok(value.title), + version: Ok(value.version), + } + } + } + #[derive(Clone, Debug)] + pub struct InitializeRequest { + client_capabilities: + ::std::result::Result, + client_info: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + protocol_version: ::std::result::Result, + } + impl ::std::default::Default for InitializeRequest { + fn default() -> Self { + Self { + client_capabilities: Ok(super::defaults::initialize_request_client_capabilities()), + client_info: Ok(Default::default()), + meta: Ok(Default::default()), + protocol_version: Err("no value supplied for protocol_version".to_string()), + } + } + } + impl InitializeRequest { + pub fn client_capabilities(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.client_capabilities = value.try_into().map_err(|e| { + format!("error converting supplied value for client_capabilities: {e}") + }); + self + } + pub fn client_info(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.client_info = value + .try_into() + .map_err(|e| format!("error converting supplied value for client_info: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn protocol_version(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.protocol_version = value + .try_into() + .map_err(|e| format!("error converting supplied value for protocol_version: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::InitializeRequest { + type Error = super::error::ConversionError; + fn try_from( + value: InitializeRequest, + ) -> ::std::result::Result { + Ok(Self { + client_capabilities: value.client_capabilities?, + client_info: value.client_info?, + meta: value.meta?, + protocol_version: value.protocol_version?, + }) + } + } + impl ::std::convert::From for InitializeRequest { + fn from(value: super::InitializeRequest) -> Self { + Self { + client_capabilities: Ok(value.client_capabilities), + client_info: Ok(value.client_info), + meta: Ok(value.meta), + protocol_version: Ok(value.protocol_version), + } + } + } + #[derive(Clone, Debug)] + pub struct InitializeResponse { + agent_capabilities: ::std::result::Result, + agent_info: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + auth_methods: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + protocol_version: ::std::result::Result, + } + impl ::std::default::Default for InitializeResponse { + fn default() -> Self { + Self { + agent_capabilities: Ok(super::defaults::initialize_response_agent_capabilities()), + agent_info: Ok(Default::default()), + auth_methods: Ok(Default::default()), + meta: Ok(Default::default()), + protocol_version: Err("no value supplied for protocol_version".to_string()), + } + } + } + impl InitializeResponse { + pub fn agent_capabilities(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.agent_capabilities = value.try_into().map_err(|e| { + format!("error converting supplied value for agent_capabilities: {e}") + }); + self + } + pub fn agent_info(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.agent_info = value + .try_into() + .map_err(|e| format!("error converting supplied value for agent_info: {e}")); + self + } + pub fn auth_methods(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.auth_methods = value + .try_into() + .map_err(|e| format!("error converting supplied value for auth_methods: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn protocol_version(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.protocol_version = value + .try_into() + .map_err(|e| format!("error converting supplied value for protocol_version: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::InitializeResponse { + type Error = super::error::ConversionError; + fn try_from( + value: InitializeResponse, + ) -> ::std::result::Result { + Ok(Self { + agent_capabilities: value.agent_capabilities?, + agent_info: value.agent_info?, + auth_methods: value.auth_methods?, + meta: value.meta?, + protocol_version: value.protocol_version?, + }) + } + } + impl ::std::convert::From for InitializeResponse { + fn from(value: super::InitializeResponse) -> Self { + Self { + agent_capabilities: Ok(value.agent_capabilities), + agent_info: Ok(value.agent_info), + auth_methods: Ok(value.auth_methods), + meta: Ok(value.meta), + protocol_version: Ok(value.protocol_version), + } + } + } + #[derive(Clone, Debug)] + pub struct KillTerminalRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + terminal_id: ::std::result::Result, + } + impl ::std::default::Default for KillTerminalRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + terminal_id: Err("no value supplied for terminal_id".to_string()), + } + } + } + impl KillTerminalRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn terminal_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::KillTerminalRequest { + type Error = super::error::ConversionError; + fn try_from( + value: KillTerminalRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + terminal_id: value.terminal_id?, + }) + } + } + impl ::std::convert::From for KillTerminalRequest { + fn from(value: super::KillTerminalRequest) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + terminal_id: Ok(value.terminal_id), + } + } + } + #[derive(Clone, Debug)] + pub struct KillTerminalResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for KillTerminalResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl KillTerminalResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::KillTerminalResponse { + type Error = super::error::ConversionError; + fn try_from( + value: KillTerminalResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for KillTerminalResponse { + fn from(value: super::KillTerminalResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct ListSessionsRequest { + cursor: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + cwd: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for ListSessionsRequest { + fn default() -> Self { + Self { + cursor: Ok(Default::default()), + cwd: Ok(Default::default()), + meta: Ok(Default::default()), + } + } + } + impl ListSessionsRequest { + pub fn cursor(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.cursor = value + .try_into() + .map_err(|e| format!("error converting supplied value for cursor: {e}")); + self + } + pub fn cwd(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.cwd = value + .try_into() + .map_err(|e| format!("error converting supplied value for cwd: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ListSessionsRequest { + type Error = super::error::ConversionError; + fn try_from( + value: ListSessionsRequest, + ) -> ::std::result::Result { + Ok(Self { + cursor: value.cursor?, + cwd: value.cwd?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for ListSessionsRequest { + fn from(value: super::ListSessionsRequest) -> Self { + Self { + cursor: Ok(value.cursor), + cwd: Ok(value.cwd), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct ListSessionsResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + next_cursor: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + sessions: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + } + impl ::std::default::Default for ListSessionsResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + next_cursor: Ok(Default::default()), + sessions: Err("no value supplied for sessions".to_string()), + } + } + } + impl ListSessionsResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn next_cursor(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.next_cursor = value + .try_into() + .map_err(|e| format!("error converting supplied value for next_cursor: {e}")); + self + } + pub fn sessions(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.sessions = value + .try_into() + .map_err(|e| format!("error converting supplied value for sessions: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ListSessionsResponse { + type Error = super::error::ConversionError; + fn try_from( + value: ListSessionsResponse, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + next_cursor: value.next_cursor?, + sessions: value.sessions?, + }) + } + } + impl ::std::convert::From for ListSessionsResponse { + fn from(value: super::ListSessionsResponse) -> Self { + Self { + meta: Ok(value.meta), + next_cursor: Ok(value.next_cursor), + sessions: Ok(value.sessions), + } + } + } + #[derive(Clone, Debug)] + pub struct LoadSessionRequest { + additional_directories: + ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>, + cwd: ::std::result::Result<::std::string::String, ::std::string::String>, + mcp_servers: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + } + impl ::std::default::Default for LoadSessionRequest { + fn default() -> Self { + Self { + additional_directories: Ok(Default::default()), + cwd: Err("no value supplied for cwd".to_string()), + mcp_servers: Err("no value supplied for mcp_servers".to_string()), + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl LoadSessionRequest { + pub fn additional_directories(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.additional_directories = value.try_into().map_err(|e| { + format!("error converting supplied value for additional_directories: {e}") + }); + self + } + pub fn cwd(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.cwd = value + .try_into() + .map_err(|e| format!("error converting supplied value for cwd: {e}")); + self + } + pub fn mcp_servers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.mcp_servers = value + .try_into() + .map_err(|e| format!("error converting supplied value for mcp_servers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::LoadSessionRequest { + type Error = super::error::ConversionError; + fn try_from( + value: LoadSessionRequest, + ) -> ::std::result::Result { + Ok(Self { + additional_directories: value.additional_directories?, + cwd: value.cwd?, + mcp_servers: value.mcp_servers?, + meta: value.meta?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for LoadSessionRequest { + fn from(value: super::LoadSessionRequest) -> Self { + Self { + additional_directories: Ok(value.additional_directories), + cwd: Ok(value.cwd), + mcp_servers: Ok(value.mcp_servers), + meta: Ok(value.meta), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct LoadSessionResponse { + config_options: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + modes: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for LoadSessionResponse { + fn default() -> Self { + Self { + config_options: Ok(Default::default()), + meta: Ok(Default::default()), + modes: Ok(Default::default()), + } + } + } + impl LoadSessionResponse { + pub fn config_options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.config_options = value + .try_into() + .map_err(|e| format!("error converting supplied value for config_options: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn modes(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.modes = value + .try_into() + .map_err(|e| format!("error converting supplied value for modes: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::LoadSessionResponse { + type Error = super::error::ConversionError; + fn try_from( + value: LoadSessionResponse, + ) -> ::std::result::Result { + Ok(Self { + config_options: value.config_options?, + meta: value.meta?, + modes: value.modes?, + }) + } + } + impl ::std::convert::From for LoadSessionResponse { + fn from(value: super::LoadSessionResponse) -> Self { + Self { + config_options: Ok(value.config_options), + meta: Ok(value.meta), + modes: Ok(value.modes), + } + } + } + #[derive(Clone, Debug)] + pub struct LogoutCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for LogoutCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl LogoutCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::LogoutCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: LogoutCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for LogoutCapabilities { + fn from(value: super::LogoutCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct LogoutRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for LogoutRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl LogoutRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::LogoutRequest { + type Error = super::error::ConversionError; + fn try_from( + value: LogoutRequest, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for LogoutRequest { + fn from(value: super::LogoutRequest) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct LogoutResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for LogoutResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl LogoutResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::LogoutResponse { + type Error = super::error::ConversionError; + fn try_from( + value: LogoutResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for LogoutResponse { + fn from(value: super::LogoutResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct McpCapabilities { + http: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + sse: ::std::result::Result, + } + impl ::std::default::Default for McpCapabilities { + fn default() -> Self { + Self { + http: Ok(Default::default()), + meta: Ok(Default::default()), + sse: Ok(Default::default()), + } + } + } + impl McpCapabilities { + pub fn http(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.http = value + .try_into() + .map_err(|e| format!("error converting supplied value for http: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn sse(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.sse = value + .try_into() + .map_err(|e| format!("error converting supplied value for sse: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: McpCapabilities, + ) -> ::std::result::Result { + Ok(Self { + http: value.http?, + meta: value.meta?, + sse: value.sse?, + }) + } + } + impl ::std::convert::From for McpCapabilities { + fn from(value: super::McpCapabilities) -> Self { + Self { + http: Ok(value.http), + meta: Ok(value.meta), + sse: Ok(value.sse), + } + } + } + #[derive(Clone, Debug)] + pub struct McpServer { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for McpServer { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + } + } + } + impl McpServer { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpServer { + type Error = super::error::ConversionError; + fn try_from( + value: McpServer, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + }) + } + } + impl ::std::convert::From for McpServer { + fn from(value: super::McpServer) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + } + } + } + #[derive(Clone, Debug)] + pub struct McpServerHttp { + headers: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + url: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for McpServerHttp { + fn default() -> Self { + Self { + headers: Err("no value supplied for headers".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + url: Err("no value supplied for url".to_string()), + } + } + } + impl McpServerHttp { + pub fn headers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.headers = value + .try_into() + .map_err(|e| format!("error converting supplied value for headers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn url(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.url = value + .try_into() + .map_err(|e| format!("error converting supplied value for url: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpServerHttp { + type Error = super::error::ConversionError; + fn try_from( + value: McpServerHttp, + ) -> ::std::result::Result { + Ok(Self { + headers: value.headers?, + meta: value.meta?, + name: value.name?, + url: value.url?, + }) + } + } + impl ::std::convert::From for McpServerHttp { + fn from(value: super::McpServerHttp) -> Self { + Self { + headers: Ok(value.headers), + meta: Ok(value.meta), + name: Ok(value.name), + url: Ok(value.url), + } + } + } + #[derive(Clone, Debug)] + pub struct McpServerSse { + headers: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + url: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for McpServerSse { + fn default() -> Self { + Self { + headers: Err("no value supplied for headers".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + url: Err("no value supplied for url".to_string()), + } + } + } + impl McpServerSse { + pub fn headers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.headers = value + .try_into() + .map_err(|e| format!("error converting supplied value for headers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn url(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.url = value + .try_into() + .map_err(|e| format!("error converting supplied value for url: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpServerSse { + type Error = super::error::ConversionError; + fn try_from( + value: McpServerSse, + ) -> ::std::result::Result { + Ok(Self { + headers: value.headers?, + meta: value.meta?, + name: value.name?, + url: value.url?, + }) + } + } + impl ::std::convert::From for McpServerSse { + fn from(value: super::McpServerSse) -> Self { + Self { + headers: Ok(value.headers), + meta: Ok(value.meta), + name: Ok(value.name), + url: Ok(value.url), + } + } + } + #[derive(Clone, Debug)] + pub struct McpServerStdio { + args: ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>, + command: ::std::result::Result<::std::string::String, ::std::string::String>, + env: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for McpServerStdio { + fn default() -> Self { + Self { + args: Err("no value supplied for args".to_string()), + command: Err("no value supplied for command".to_string()), + env: Err("no value supplied for env".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + } + } + } + impl McpServerStdio { + pub fn args(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.args = value + .try_into() + .map_err(|e| format!("error converting supplied value for args: {e}")); + self + } + pub fn command(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.command = value + .try_into() + .map_err(|e| format!("error converting supplied value for command: {e}")); + self + } + pub fn env(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.env = value + .try_into() + .map_err(|e| format!("error converting supplied value for env: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpServerStdio { + type Error = super::error::ConversionError; + fn try_from( + value: McpServerStdio, + ) -> ::std::result::Result { + Ok(Self { + args: value.args?, + command: value.command?, + env: value.env?, + meta: value.meta?, + name: value.name?, + }) + } + } + impl ::std::convert::From for McpServerStdio { + fn from(value: super::McpServerStdio) -> Self { + Self { + args: Ok(value.args), + command: Ok(value.command), + env: Ok(value.env), + meta: Ok(value.meta), + name: Ok(value.name), + } + } + } + #[derive(Clone, Debug)] + pub struct McpServerSubtype0 { + headers: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + type_: ::std::result::Result<::std::string::String, ::std::string::String>, + url: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for McpServerSubtype0 { + fn default() -> Self { + Self { + headers: Err("no value supplied for headers".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + type_: Err("no value supplied for type_".to_string()), + url: Err("no value supplied for url".to_string()), + } + } + } + impl McpServerSubtype0 { + pub fn headers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.headers = value + .try_into() + .map_err(|e| format!("error converting supplied value for headers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn type_(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.type_ = value + .try_into() + .map_err(|e| format!("error converting supplied value for type_: {e}")); + self + } + pub fn url(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.url = value + .try_into() + .map_err(|e| format!("error converting supplied value for url: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpServerSubtype0 { + type Error = super::error::ConversionError; + fn try_from( + value: McpServerSubtype0, + ) -> ::std::result::Result { + Ok(Self { + headers: value.headers?, + meta: value.meta?, + name: value.name?, + type_: value.type_?, + url: value.url?, + }) + } + } + impl ::std::convert::From for McpServerSubtype0 { + fn from(value: super::McpServerSubtype0) -> Self { + Self { + headers: Ok(value.headers), + meta: Ok(value.meta), + name: Ok(value.name), + type_: Ok(value.type_), + url: Ok(value.url), + } + } + } + #[derive(Clone, Debug)] + pub struct McpServerSubtype1 { + headers: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + type_: ::std::result::Result<::std::string::String, ::std::string::String>, + url: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for McpServerSubtype1 { + fn default() -> Self { + Self { + headers: Err("no value supplied for headers".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + type_: Err("no value supplied for type_".to_string()), + url: Err("no value supplied for url".to_string()), + } + } + } + impl McpServerSubtype1 { + pub fn headers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.headers = value + .try_into() + .map_err(|e| format!("error converting supplied value for headers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn type_(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.type_ = value + .try_into() + .map_err(|e| format!("error converting supplied value for type_: {e}")); + self + } + pub fn url(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.url = value + .try_into() + .map_err(|e| format!("error converting supplied value for url: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::McpServerSubtype1 { + type Error = super::error::ConversionError; + fn try_from( + value: McpServerSubtype1, + ) -> ::std::result::Result { + Ok(Self { + headers: value.headers?, + meta: value.meta?, + name: value.name?, + type_: value.type_?, + url: value.url?, + }) + } + } + impl ::std::convert::From for McpServerSubtype1 { + fn from(value: super::McpServerSubtype1) -> Self { + Self { + headers: Ok(value.headers), + meta: Ok(value.meta), + name: Ok(value.name), + type_: Ok(value.type_), + url: Ok(value.url), + } + } + } + #[derive(Clone, Debug)] + pub struct NewSessionRequest { + additional_directories: + ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>, + cwd: ::std::result::Result<::std::string::String, ::std::string::String>, + mcp_servers: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for NewSessionRequest { + fn default() -> Self { + Self { + additional_directories: Ok(Default::default()), + cwd: Err("no value supplied for cwd".to_string()), + mcp_servers: Err("no value supplied for mcp_servers".to_string()), + meta: Ok(Default::default()), + } + } + } + impl NewSessionRequest { + pub fn additional_directories(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.additional_directories = value.try_into().map_err(|e| { + format!("error converting supplied value for additional_directories: {e}") + }); + self + } + pub fn cwd(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.cwd = value + .try_into() + .map_err(|e| format!("error converting supplied value for cwd: {e}")); + self + } + pub fn mcp_servers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.mcp_servers = value + .try_into() + .map_err(|e| format!("error converting supplied value for mcp_servers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::NewSessionRequest { + type Error = super::error::ConversionError; + fn try_from( + value: NewSessionRequest, + ) -> ::std::result::Result { + Ok(Self { + additional_directories: value.additional_directories?, + cwd: value.cwd?, + mcp_servers: value.mcp_servers?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for NewSessionRequest { + fn from(value: super::NewSessionRequest) -> Self { + Self { + additional_directories: Ok(value.additional_directories), + cwd: Ok(value.cwd), + mcp_servers: Ok(value.mcp_servers), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct NewSessionResponse { + config_options: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + modes: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + session_id: ::std::result::Result, + } + impl ::std::default::Default for NewSessionResponse { + fn default() -> Self { + Self { + config_options: Ok(Default::default()), + meta: Ok(Default::default()), + modes: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl NewSessionResponse { + pub fn config_options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.config_options = value + .try_into() + .map_err(|e| format!("error converting supplied value for config_options: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn modes(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.modes = value + .try_into() + .map_err(|e| format!("error converting supplied value for modes: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::NewSessionResponse { + type Error = super::error::ConversionError; + fn try_from( + value: NewSessionResponse, + ) -> ::std::result::Result { + Ok(Self { + config_options: value.config_options?, + meta: value.meta?, + modes: value.modes?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for NewSessionResponse { + fn from(value: super::NewSessionResponse) -> Self { + Self { + config_options: Ok(value.config_options), + meta: Ok(value.meta), + modes: Ok(value.modes), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct PermissionOption { + kind: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + option_id: ::std::result::Result, + } + impl ::std::default::Default for PermissionOption { + fn default() -> Self { + Self { + kind: Err("no value supplied for kind".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + option_id: Err("no value supplied for option_id".to_string()), + } + } + } + impl PermissionOption { + pub fn kind(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.kind = value + .try_into() + .map_err(|e| format!("error converting supplied value for kind: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn option_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.option_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for option_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::PermissionOption { + type Error = super::error::ConversionError; + fn try_from( + value: PermissionOption, + ) -> ::std::result::Result { + Ok(Self { + kind: value.kind?, + meta: value.meta?, + name: value.name?, + option_id: value.option_id?, + }) + } + } + impl ::std::convert::From for PermissionOption { + fn from(value: super::PermissionOption) -> Self { + Self { + kind: Ok(value.kind), + meta: Ok(value.meta), + name: Ok(value.name), + option_id: Ok(value.option_id), + } + } + } + #[derive(Clone, Debug)] + pub struct Plan { + entries: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for Plan { + fn default() -> Self { + Self { + entries: Err("no value supplied for entries".to_string()), + meta: Ok(Default::default()), + } + } + } + impl Plan { + pub fn entries(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.entries = value + .try_into() + .map_err(|e| format!("error converting supplied value for entries: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Plan { + type Error = super::error::ConversionError; + fn try_from(value: Plan) -> ::std::result::Result { + Ok(Self { + entries: value.entries?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for Plan { + fn from(value: super::Plan) -> Self { + Self { + entries: Ok(value.entries), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct PlanEntry { + content: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + priority: ::std::result::Result, + status: ::std::result::Result, + } + impl ::std::default::Default for PlanEntry { + fn default() -> Self { + Self { + content: Err("no value supplied for content".to_string()), + meta: Ok(Default::default()), + priority: Err("no value supplied for priority".to_string()), + status: Err("no value supplied for status".to_string()), + } + } + } + impl PlanEntry { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn priority(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.priority = value + .try_into() + .map_err(|e| format!("error converting supplied value for priority: {e}")); + self + } + pub fn status(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.status = value + .try_into() + .map_err(|e| format!("error converting supplied value for status: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::PlanEntry { + type Error = super::error::ConversionError; + fn try_from( + value: PlanEntry, + ) -> ::std::result::Result { + Ok(Self { + content: value.content?, + meta: value.meta?, + priority: value.priority?, + status: value.status?, + }) + } + } + impl ::std::convert::From for PlanEntry { + fn from(value: super::PlanEntry) -> Self { + Self { + content: Ok(value.content), + meta: Ok(value.meta), + priority: Ok(value.priority), + status: Ok(value.status), + } + } + } + #[derive(Clone, Debug)] + pub struct PromptCapabilities { + audio: ::std::result::Result, + embedded_context: ::std::result::Result, + image: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for PromptCapabilities { + fn default() -> Self { + Self { + audio: Ok(Default::default()), + embedded_context: Ok(Default::default()), + image: Ok(Default::default()), + meta: Ok(Default::default()), + } + } + } + impl PromptCapabilities { + pub fn audio(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.audio = value + .try_into() + .map_err(|e| format!("error converting supplied value for audio: {e}")); + self + } + pub fn embedded_context(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.embedded_context = value + .try_into() + .map_err(|e| format!("error converting supplied value for embedded_context: {e}")); + self + } + pub fn image(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.image = value + .try_into() + .map_err(|e| format!("error converting supplied value for image: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::PromptCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: PromptCapabilities, + ) -> ::std::result::Result { + Ok(Self { + audio: value.audio?, + embedded_context: value.embedded_context?, + image: value.image?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for PromptCapabilities { + fn from(value: super::PromptCapabilities) -> Self { + Self { + audio: Ok(value.audio), + embedded_context: Ok(value.embedded_context), + image: Ok(value.image), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct PromptRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + prompt: ::std::result::Result<::std::vec::Vec, ::std::string::String>, + session_id: ::std::result::Result, + } + impl ::std::default::Default for PromptRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + prompt: Err("no value supplied for prompt".to_string()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl PromptRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn prompt(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.prompt = value + .try_into() + .map_err(|e| format!("error converting supplied value for prompt: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::PromptRequest { + type Error = super::error::ConversionError; + fn try_from( + value: PromptRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + prompt: value.prompt?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for PromptRequest { + fn from(value: super::PromptRequest) -> Self { + Self { + meta: Ok(value.meta), + prompt: Ok(value.prompt), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct PromptResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + stop_reason: ::std::result::Result, + } + impl ::std::default::Default for PromptResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + stop_reason: Err("no value supplied for stop_reason".to_string()), + } + } + } + impl PromptResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn stop_reason(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.stop_reason = value + .try_into() + .map_err(|e| format!("error converting supplied value for stop_reason: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::PromptResponse { + type Error = super::error::ConversionError; + fn try_from( + value: PromptResponse, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + stop_reason: value.stop_reason?, + }) + } + } + impl ::std::convert::From for PromptResponse { + fn from(value: super::PromptResponse) -> Self { + Self { + meta: Ok(value.meta), + stop_reason: Ok(value.stop_reason), + } + } + } + #[derive(Clone, Debug)] + pub struct ProtocolLevel { + jsonrpc: ::std::result::Result, + method: ::std::result::Result<::std::string::String, ::std::string::String>, + params: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for ProtocolLevel { + fn default() -> Self { + Self { + jsonrpc: Err("no value supplied for jsonrpc".to_string()), + method: Err("no value supplied for method".to_string()), + params: Ok(Default::default()), + } + } + } + impl ProtocolLevel { + pub fn jsonrpc(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.jsonrpc = value + .try_into() + .map_err(|e| format!("error converting supplied value for jsonrpc: {e}")); + self + } + pub fn method(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.method = value + .try_into() + .map_err(|e| format!("error converting supplied value for method: {e}")); + self + } + pub fn params(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.params = value + .try_into() + .map_err(|e| format!("error converting supplied value for params: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ProtocolLevel { + type Error = super::error::ConversionError; + fn try_from( + value: ProtocolLevel, + ) -> ::std::result::Result { + Ok(Self { + jsonrpc: value.jsonrpc?, + method: value.method?, + params: value.params?, + }) + } + } + impl ::std::convert::From for ProtocolLevel { + fn from(value: super::ProtocolLevel) -> Self { + Self { + jsonrpc: Ok(value.jsonrpc), + method: Ok(value.method), + params: Ok(value.params), + } + } + } + #[derive(Clone, Debug)] + pub struct ReadTextFileRequest { + limit: ::std::result::Result<::std::option::Option, ::std::string::String>, + line: ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + path: ::std::result::Result<::std::string::String, ::std::string::String>, + session_id: ::std::result::Result, + } + impl ::std::default::Default for ReadTextFileRequest { + fn default() -> Self { + Self { + limit: Ok(Default::default()), + line: Ok(Default::default()), + meta: Ok(Default::default()), + path: Err("no value supplied for path".to_string()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl ReadTextFileRequest { + pub fn limit(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.limit = value + .try_into() + .map_err(|e| format!("error converting supplied value for limit: {e}")); + self + } + pub fn line(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.line = value + .try_into() + .map_err(|e| format!("error converting supplied value for line: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn path(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.path = value + .try_into() + .map_err(|e| format!("error converting supplied value for path: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ReadTextFileRequest { + type Error = super::error::ConversionError; + fn try_from( + value: ReadTextFileRequest, + ) -> ::std::result::Result { + Ok(Self { + limit: value.limit?, + line: value.line?, + meta: value.meta?, + path: value.path?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for ReadTextFileRequest { + fn from(value: super::ReadTextFileRequest) -> Self { + Self { + limit: Ok(value.limit), + line: Ok(value.line), + meta: Ok(value.meta), + path: Ok(value.path), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct ReadTextFileResponse { + content: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for ReadTextFileResponse { + fn default() -> Self { + Self { + content: Err("no value supplied for content".to_string()), + meta: Ok(Default::default()), + } + } + } + impl ReadTextFileResponse { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ReadTextFileResponse { + type Error = super::error::ConversionError; + fn try_from( + value: ReadTextFileResponse, + ) -> ::std::result::Result { + Ok(Self { + content: value.content?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for ReadTextFileResponse { + fn from(value: super::ReadTextFileResponse) -> Self { + Self { + content: Ok(value.content), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct ReleaseTerminalRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + terminal_id: ::std::result::Result, + } + impl ::std::default::Default for ReleaseTerminalRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + terminal_id: Err("no value supplied for terminal_id".to_string()), + } + } + } + impl ReleaseTerminalRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn terminal_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ReleaseTerminalRequest { + type Error = super::error::ConversionError; + fn try_from( + value: ReleaseTerminalRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + terminal_id: value.terminal_id?, + }) + } + } + impl ::std::convert::From for ReleaseTerminalRequest { + fn from(value: super::ReleaseTerminalRequest) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + terminal_id: Ok(value.terminal_id), + } + } + } + #[derive(Clone, Debug)] + pub struct ReleaseTerminalResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for ReleaseTerminalResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl ReleaseTerminalResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ReleaseTerminalResponse { + type Error = super::error::ConversionError; + fn try_from( + value: ReleaseTerminalResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for ReleaseTerminalResponse { + fn from(value: super::ReleaseTerminalResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct RequestPermissionRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + options: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + session_id: ::std::result::Result, + tool_call: ::std::result::Result, + } + impl ::std::default::Default for RequestPermissionRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + options: Err("no value supplied for options".to_string()), + session_id: Err("no value supplied for session_id".to_string()), + tool_call: Err("no value supplied for tool_call".to_string()), + } + } + } + impl RequestPermissionRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.options = value + .try_into() + .map_err(|e| format!("error converting supplied value for options: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn tool_call(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.tool_call = value + .try_into() + .map_err(|e| format!("error converting supplied value for tool_call: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::RequestPermissionRequest { + type Error = super::error::ConversionError; + fn try_from( + value: RequestPermissionRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + options: value.options?, + session_id: value.session_id?, + tool_call: value.tool_call?, + }) + } + } + impl ::std::convert::From for RequestPermissionRequest { + fn from(value: super::RequestPermissionRequest) -> Self { + Self { + meta: Ok(value.meta), + options: Ok(value.options), + session_id: Ok(value.session_id), + tool_call: Ok(value.tool_call), + } + } + } + #[derive(Clone, Debug)] + pub struct RequestPermissionResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + outcome: ::std::result::Result, + } + impl ::std::default::Default for RequestPermissionResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + outcome: Err("no value supplied for outcome".to_string()), + } + } + } + impl RequestPermissionResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn outcome(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.outcome = value + .try_into() + .map_err(|e| format!("error converting supplied value for outcome: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::RequestPermissionResponse { + type Error = super::error::ConversionError; + fn try_from( + value: RequestPermissionResponse, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + outcome: value.outcome?, + }) + } + } + impl ::std::convert::From for RequestPermissionResponse { + fn from(value: super::RequestPermissionResponse) -> Self { + Self { + meta: Ok(value.meta), + outcome: Ok(value.outcome), + } + } + } + #[derive(Clone, Debug)] + pub struct ResourceLink { + annotations: + ::std::result::Result<::std::option::Option, ::std::string::String>, + description: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + mime_type: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + size: ::std::result::Result<::std::option::Option, ::std::string::String>, + title: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + uri: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for ResourceLink { + fn default() -> Self { + Self { + annotations: Ok(Default::default()), + description: Ok(Default::default()), + meta: Ok(Default::default()), + mime_type: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + size: Ok(Default::default()), + title: Ok(Default::default()), + uri: Err("no value supplied for uri".to_string()), + } + } + } + impl ResourceLink { + pub fn annotations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.annotations = value + .try_into() + .map_err(|e| format!("error converting supplied value for annotations: {e}")); + self + } + pub fn description(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.description = value + .try_into() + .map_err(|e| format!("error converting supplied value for description: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn mime_type(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.mime_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for mime_type: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn size(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.size = value + .try_into() + .map_err(|e| format!("error converting supplied value for size: {e}")); + self + } + pub fn title(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.title = value + .try_into() + .map_err(|e| format!("error converting supplied value for title: {e}")); + self + } + pub fn uri(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.uri = value + .try_into() + .map_err(|e| format!("error converting supplied value for uri: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ResourceLink { + type Error = super::error::ConversionError; + fn try_from( + value: ResourceLink, + ) -> ::std::result::Result { + Ok(Self { + annotations: value.annotations?, + description: value.description?, + meta: value.meta?, + mime_type: value.mime_type?, + name: value.name?, + size: value.size?, + title: value.title?, + uri: value.uri?, + }) + } + } + impl ::std::convert::From for ResourceLink { + fn from(value: super::ResourceLink) -> Self { + Self { + annotations: Ok(value.annotations), + description: Ok(value.description), + meta: Ok(value.meta), + mime_type: Ok(value.mime_type), + name: Ok(value.name), + size: Ok(value.size), + title: Ok(value.title), + uri: Ok(value.uri), + } + } + } + #[derive(Clone, Debug)] + pub struct ResultResult { + subtype_0: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_3: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_4: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_5: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_6: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_7: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_8: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_9: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_10: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_11: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + subtype_12: + ::std::result::Result<::std::option::Option, ::std::string::String>, + } + impl ::std::default::Default for ResultResult { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + subtype_5: Ok(Default::default()), + subtype_6: Ok(Default::default()), + subtype_7: Ok(Default::default()), + subtype_8: Ok(Default::default()), + subtype_9: Ok(Default::default()), + subtype_10: Ok(Default::default()), + subtype_11: Ok(Default::default()), + subtype_12: Ok(Default::default()), + } + } + } + impl ResultResult { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + pub fn subtype_5(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_5 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_5: {e}")); + self + } + pub fn subtype_6(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_6 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_6: {e}")); + self + } + pub fn subtype_7(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_7 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_7: {e}")); + self + } + pub fn subtype_8(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_8 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_8: {e}")); + self + } + pub fn subtype_9(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_9 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_9: {e}")); + self + } + pub fn subtype_10(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option, + >, + T::Error: ::std::fmt::Display, + { + self.subtype_10 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_10: {e}")); + self + } + pub fn subtype_11(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_11 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_11: {e}")); + self + } + pub fn subtype_12(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.subtype_12 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_12: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ResultResult { + type Error = super::error::ConversionError; + fn try_from( + value: ResultResult, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + subtype_5: value.subtype_5?, + subtype_6: value.subtype_6?, + subtype_7: value.subtype_7?, + subtype_8: value.subtype_8?, + subtype_9: value.subtype_9?, + subtype_10: value.subtype_10?, + subtype_11: value.subtype_11?, + subtype_12: value.subtype_12?, + }) + } + } + impl ::std::convert::From for ResultResult { + fn from(value: super::ResultResult) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + subtype_5: Ok(value.subtype_5), + subtype_6: Ok(value.subtype_6), + subtype_7: Ok(value.subtype_7), + subtype_8: Ok(value.subtype_8), + subtype_9: Ok(value.subtype_9), + subtype_10: Ok(value.subtype_10), + subtype_11: Ok(value.subtype_11), + subtype_12: Ok(value.subtype_12), + } + } + } + #[derive(Clone, Debug)] + pub struct ResumeSessionRequest { + additional_directories: + ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>, + cwd: ::std::result::Result<::std::string::String, ::std::string::String>, + mcp_servers: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + } + impl ::std::default::Default for ResumeSessionRequest { + fn default() -> Self { + Self { + additional_directories: Ok(Default::default()), + cwd: Err("no value supplied for cwd".to_string()), + mcp_servers: Ok(Default::default()), + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl ResumeSessionRequest { + pub fn additional_directories(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.additional_directories = value.try_into().map_err(|e| { + format!("error converting supplied value for additional_directories: {e}") + }); + self + } + pub fn cwd(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.cwd = value + .try_into() + .map_err(|e| format!("error converting supplied value for cwd: {e}")); + self + } + pub fn mcp_servers(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.mcp_servers = value + .try_into() + .map_err(|e| format!("error converting supplied value for mcp_servers: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ResumeSessionRequest { + type Error = super::error::ConversionError; + fn try_from( + value: ResumeSessionRequest, + ) -> ::std::result::Result { + Ok(Self { + additional_directories: value.additional_directories?, + cwd: value.cwd?, + mcp_servers: value.mcp_servers?, + meta: value.meta?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for ResumeSessionRequest { + fn from(value: super::ResumeSessionRequest) -> Self { + Self { + additional_directories: Ok(value.additional_directories), + cwd: Ok(value.cwd), + mcp_servers: Ok(value.mcp_servers), + meta: Ok(value.meta), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct ResumeSessionResponse { + config_options: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + modes: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for ResumeSessionResponse { + fn default() -> Self { + Self { + config_options: Ok(Default::default()), + meta: Ok(Default::default()), + modes: Ok(Default::default()), + } + } + } + impl ResumeSessionResponse { + pub fn config_options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.config_options = value + .try_into() + .map_err(|e| format!("error converting supplied value for config_options: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn modes(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.modes = value + .try_into() + .map_err(|e| format!("error converting supplied value for modes: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ResumeSessionResponse { + type Error = super::error::ConversionError; + fn try_from( + value: ResumeSessionResponse, + ) -> ::std::result::Result { + Ok(Self { + config_options: value.config_options?, + meta: value.meta?, + modes: value.modes?, + }) + } + } + impl ::std::convert::From for ResumeSessionResponse { + fn from(value: super::ResumeSessionResponse) -> Self { + Self { + config_options: Ok(value.config_options), + meta: Ok(value.meta), + modes: Ok(value.modes), + } + } + } + #[derive(Clone, Debug)] + pub struct SelectedPermissionOutcome { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + option_id: ::std::result::Result, + } + impl ::std::default::Default for SelectedPermissionOutcome { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + option_id: Err("no value supplied for option_id".to_string()), + } + } + } + impl SelectedPermissionOutcome { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn option_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.option_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for option_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SelectedPermissionOutcome { + type Error = super::error::ConversionError; + fn try_from( + value: SelectedPermissionOutcome, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + option_id: value.option_id?, + }) + } + } + impl ::std::convert::From for SelectedPermissionOutcome { + fn from(value: super::SelectedPermissionOutcome) -> Self { + Self { + meta: Ok(value.meta), + option_id: Ok(value.option_id), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionAdditionalDirectoriesCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionAdditionalDirectoriesCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl SessionAdditionalDirectoriesCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom + for super::SessionAdditionalDirectoriesCapabilities + { + type Error = super::error::ConversionError; + fn try_from( + value: SessionAdditionalDirectoriesCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From + for SessionAdditionalDirectoriesCapabilities + { + fn from(value: super::SessionAdditionalDirectoriesCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionCapabilities { + additional_directories: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + close: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + delete: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + list: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + resume: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionCapabilities { + fn default() -> Self { + Self { + additional_directories: Ok(Default::default()), + close: Ok(Default::default()), + delete: Ok(Default::default()), + list: Ok(Default::default()), + meta: Ok(Default::default()), + resume: Ok(Default::default()), + } + } + } + impl SessionCapabilities { + pub fn additional_directories(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option, + >, + T::Error: ::std::fmt::Display, + { + self.additional_directories = value.try_into().map_err(|e| { + format!("error converting supplied value for additional_directories: {e}") + }); + self + } + pub fn close(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.close = value + .try_into() + .map_err(|e| format!("error converting supplied value for close: {e}")); + self + } + pub fn delete(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.delete = value + .try_into() + .map_err(|e| format!("error converting supplied value for delete: {e}")); + self + } + pub fn list(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.list = value + .try_into() + .map_err(|e| format!("error converting supplied value for list: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn resume(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.resume = value + .try_into() + .map_err(|e| format!("error converting supplied value for resume: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: SessionCapabilities, + ) -> ::std::result::Result { + Ok(Self { + additional_directories: value.additional_directories?, + close: value.close?, + delete: value.delete?, + list: value.list?, + meta: value.meta?, + resume: value.resume?, + }) + } + } + impl ::std::convert::From for SessionCapabilities { + fn from(value: super::SessionCapabilities) -> Self { + Self { + additional_directories: Ok(value.additional_directories), + close: Ok(value.close), + delete: Ok(value.delete), + list: Ok(value.list), + meta: Ok(value.meta), + resume: Ok(value.resume), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionCloseCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionCloseCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl SessionCloseCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionCloseCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: SessionCloseCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for SessionCloseCapabilities { + fn from(value: super::SessionCloseCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigBoolean { + current_value: ::std::result::Result, + } + impl ::std::default::Default for SessionConfigBoolean { + fn default() -> Self { + Self { + current_value: Err("no value supplied for current_value".to_string()), + } + } + } + impl SessionConfigBoolean { + pub fn current_value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.current_value = value + .try_into() + .map_err(|e| format!("error converting supplied value for current_value: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionConfigBoolean { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigBoolean, + ) -> ::std::result::Result { + Ok(Self { + current_value: value.current_value?, + }) + } + } + impl ::std::convert::From for SessionConfigBoolean { + fn from(value: super::SessionConfigBoolean) -> Self { + Self { + current_value: Ok(value.current_value), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigOptionCategory { + subtype_0: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + subtype_2: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + subtype_3: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + subtype_4: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionConfigOptionCategory { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + subtype_2: Ok(Default::default()), + subtype_3: Ok(Default::default()), + subtype_4: Ok(Default::default()), + } + } + } + impl SessionConfigOptionCategory { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + pub fn subtype_2(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.subtype_2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_2: {e}")); + self + } + pub fn subtype_3(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.subtype_3 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_3: {e}")); + self + } + pub fn subtype_4(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.subtype_4 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_4: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionConfigOptionCategory { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigOptionCategory, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + subtype_2: value.subtype_2?, + subtype_3: value.subtype_3?, + subtype_4: value.subtype_4?, + }) + } + } + impl ::std::convert::From for SessionConfigOptionCategory { + fn from(value: super::SessionConfigOptionCategory) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + subtype_2: Ok(value.subtype_2), + subtype_3: Ok(value.subtype_3), + subtype_4: Ok(value.subtype_4), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigOptionsCapabilities { + boolean: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionConfigOptionsCapabilities { + fn default() -> Self { + Self { + boolean: Ok(Default::default()), + meta: Ok(Default::default()), + } + } + } + impl SessionConfigOptionsCapabilities { + pub fn boolean(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option, + >, + T::Error: ::std::fmt::Display, + { + self.boolean = value + .try_into() + .map_err(|e| format!("error converting supplied value for boolean: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom + for super::SessionConfigOptionsCapabilities + { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigOptionsCapabilities, + ) -> ::std::result::Result { + Ok(Self { + boolean: value.boolean?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From + for SessionConfigOptionsCapabilities + { + fn from(value: super::SessionConfigOptionsCapabilities) -> Self { + Self { + boolean: Ok(value.boolean), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigSelect { + current_value: ::std::result::Result, + options: ::std::result::Result, + } + impl ::std::default::Default for SessionConfigSelect { + fn default() -> Self { + Self { + current_value: Err("no value supplied for current_value".to_string()), + options: Err("no value supplied for options".to_string()), + } + } + } + impl SessionConfigSelect { + pub fn current_value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.current_value = value + .try_into() + .map_err(|e| format!("error converting supplied value for current_value: {e}")); + self + } + pub fn options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.options = value + .try_into() + .map_err(|e| format!("error converting supplied value for options: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionConfigSelect { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigSelect, + ) -> ::std::result::Result { + Ok(Self { + current_value: value.current_value?, + options: value.options?, + }) + } + } + impl ::std::convert::From for SessionConfigSelect { + fn from(value: super::SessionConfigSelect) -> Self { + Self { + current_value: Ok(value.current_value), + options: Ok(value.options), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigSelectGroup { + group: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + options: ::std::result::Result< + ::std::vec::Vec, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionConfigSelectGroup { + fn default() -> Self { + Self { + group: Err("no value supplied for group".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + options: Err("no value supplied for options".to_string()), + } + } + } + impl SessionConfigSelectGroup { + pub fn group(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.group = value + .try_into() + .map_err(|e| format!("error converting supplied value for group: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.options = value + .try_into() + .map_err(|e| format!("error converting supplied value for options: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionConfigSelectGroup { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigSelectGroup, + ) -> ::std::result::Result { + Ok(Self { + group: value.group?, + meta: value.meta?, + name: value.name?, + options: value.options?, + }) + } + } + impl ::std::convert::From for SessionConfigSelectGroup { + fn from(value: super::SessionConfigSelectGroup) -> Self { + Self { + group: Ok(value.group), + meta: Ok(value.meta), + name: Ok(value.name), + options: Ok(value.options), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigSelectOption { + description: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + value: ::std::result::Result, + } + impl ::std::default::Default for SessionConfigSelectOption { + fn default() -> Self { + Self { + description: Ok(Default::default()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + value: Err("no value supplied for value".to_string()), + } + } + } + impl SessionConfigSelectOption { + pub fn description(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.description = value + .try_into() + .map_err(|e| format!("error converting supplied value for description: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + pub fn value(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.value = value + .try_into() + .map_err(|e| format!("error converting supplied value for value: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionConfigSelectOption { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigSelectOption, + ) -> ::std::result::Result { + Ok(Self { + description: value.description?, + meta: value.meta?, + name: value.name?, + value: value.value?, + }) + } + } + impl ::std::convert::From for SessionConfigSelectOption { + fn from(value: super::SessionConfigSelectOption) -> Self { + Self { + description: Ok(value.description), + meta: Ok(value.meta), + name: Ok(value.name), + value: Ok(value.value), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionConfigSelectOptions { + subtype_0: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + subtype_1: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionConfigSelectOptions { + fn default() -> Self { + Self { + subtype_0: Ok(Default::default()), + subtype_1: Ok(Default::default()), + } + } + } + impl SessionConfigSelectOptions { + pub fn subtype_0(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.subtype_0 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_0: {e}")); + self + } + pub fn subtype_1(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.subtype_1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for subtype_1: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionConfigSelectOptions { + type Error = super::error::ConversionError; + fn try_from( + value: SessionConfigSelectOptions, + ) -> ::std::result::Result { + Ok(Self { + subtype_0: value.subtype_0?, + subtype_1: value.subtype_1?, + }) + } + } + impl ::std::convert::From for SessionConfigSelectOptions { + fn from(value: super::SessionConfigSelectOptions) -> Self { + Self { + subtype_0: Ok(value.subtype_0), + subtype_1: Ok(value.subtype_1), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionDeleteCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionDeleteCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl SessionDeleteCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionDeleteCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: SessionDeleteCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for SessionDeleteCapabilities { + fn from(value: super::SessionDeleteCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionInfo { + additional_directories: + ::std::result::Result<::std::vec::Vec<::std::string::String>, ::std::string::String>, + cwd: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + title: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + updated_at: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionInfo { + fn default() -> Self { + Self { + additional_directories: Ok(Default::default()), + cwd: Err("no value supplied for cwd".to_string()), + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + title: Ok(Default::default()), + updated_at: Ok(Default::default()), + } + } + } + impl SessionInfo { + pub fn additional_directories(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.additional_directories = value.try_into().map_err(|e| { + format!("error converting supplied value for additional_directories: {e}") + }); + self + } + pub fn cwd(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.cwd = value + .try_into() + .map_err(|e| format!("error converting supplied value for cwd: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn title(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.title = value + .try_into() + .map_err(|e| format!("error converting supplied value for title: {e}")); + self + } + pub fn updated_at(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.updated_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for updated_at: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionInfo { + type Error = super::error::ConversionError; + fn try_from( + value: SessionInfo, + ) -> ::std::result::Result { + Ok(Self { + additional_directories: value.additional_directories?, + cwd: value.cwd?, + meta: value.meta?, + session_id: value.session_id?, + title: value.title?, + updated_at: value.updated_at?, + }) + } + } + impl ::std::convert::From for SessionInfo { + fn from(value: super::SessionInfo) -> Self { + Self { + additional_directories: Ok(value.additional_directories), + cwd: Ok(value.cwd), + meta: Ok(value.meta), + session_id: Ok(value.session_id), + title: Ok(value.title), + updated_at: Ok(value.updated_at), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionInfoUpdate { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + title: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + updated_at: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionInfoUpdate { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + title: Ok(Default::default()), + updated_at: Ok(Default::default()), + } + } + } + impl SessionInfoUpdate { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn title(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.title = value + .try_into() + .map_err(|e| format!("error converting supplied value for title: {e}")); + self + } + pub fn updated_at(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.updated_at = value + .try_into() + .map_err(|e| format!("error converting supplied value for updated_at: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionInfoUpdate { + type Error = super::error::ConversionError; + fn try_from( + value: SessionInfoUpdate, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + title: value.title?, + updated_at: value.updated_at?, + }) + } + } + impl ::std::convert::From for SessionInfoUpdate { + fn from(value: super::SessionInfoUpdate) -> Self { + Self { + meta: Ok(value.meta), + title: Ok(value.title), + updated_at: Ok(value.updated_at), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionListCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionListCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl SessionListCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionListCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: SessionListCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for SessionListCapabilities { + fn from(value: super::SessionListCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionMode { + description: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + id: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + name: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for SessionMode { + fn default() -> Self { + Self { + description: Ok(Default::default()), + id: Err("no value supplied for id".to_string()), + meta: Ok(Default::default()), + name: Err("no value supplied for name".to_string()), + } + } + } + impl SessionMode { + pub fn description(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.description = value + .try_into() + .map_err(|e| format!("error converting supplied value for description: {e}")); + self + } + pub fn id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.id = value + .try_into() + .map_err(|e| format!("error converting supplied value for id: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn name(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.name = value + .try_into() + .map_err(|e| format!("error converting supplied value for name: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionMode { + type Error = super::error::ConversionError; + fn try_from( + value: SessionMode, + ) -> ::std::result::Result { + Ok(Self { + description: value.description?, + id: value.id?, + meta: value.meta?, + name: value.name?, + }) + } + } + impl ::std::convert::From for SessionMode { + fn from(value: super::SessionMode) -> Self { + Self { + description: Ok(value.description), + id: Ok(value.id), + meta: Ok(value.meta), + name: Ok(value.name), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionModeState { + available_modes: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + current_mode_id: ::std::result::Result, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionModeState { + fn default() -> Self { + Self { + available_modes: Err("no value supplied for available_modes".to_string()), + current_mode_id: Err("no value supplied for current_mode_id".to_string()), + meta: Ok(Default::default()), + } + } + } + impl SessionModeState { + pub fn available_modes(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.available_modes = value + .try_into() + .map_err(|e| format!("error converting supplied value for available_modes: {e}")); + self + } + pub fn current_mode_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.current_mode_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for current_mode_id: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionModeState { + type Error = super::error::ConversionError; + fn try_from( + value: SessionModeState, + ) -> ::std::result::Result { + Ok(Self { + available_modes: value.available_modes?, + current_mode_id: value.current_mode_id?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for SessionModeState { + fn from(value: super::SessionModeState) -> Self { + Self { + available_modes: Ok(value.available_modes), + current_mode_id: Ok(value.current_mode_id), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionNotification { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + update: ::std::result::Result, + } + impl ::std::default::Default for SessionNotification { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + update: Err("no value supplied for update".to_string()), + } + } + } + impl SessionNotification { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn update(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.update = value + .try_into() + .map_err(|e| format!("error converting supplied value for update: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionNotification { + type Error = super::error::ConversionError; + fn try_from( + value: SessionNotification, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + update: value.update?, + }) + } + } + impl ::std::convert::From for SessionNotification { + fn from(value: super::SessionNotification) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + update: Ok(value.update), + } + } + } + #[derive(Clone, Debug)] + pub struct SessionResumeCapabilities { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SessionResumeCapabilities { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl SessionResumeCapabilities { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SessionResumeCapabilities { + type Error = super::error::ConversionError; + fn try_from( + value: SessionResumeCapabilities, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for SessionResumeCapabilities { + fn from(value: super::SessionResumeCapabilities) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SetSessionConfigOptionResponse { + config_options: ::std::result::Result< + ::std::vec::Vec, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SetSessionConfigOptionResponse { + fn default() -> Self { + Self { + config_options: Err("no value supplied for config_options".to_string()), + meta: Ok(Default::default()), + } + } + } + impl SetSessionConfigOptionResponse { + pub fn config_options(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.config_options = value + .try_into() + .map_err(|e| format!("error converting supplied value for config_options: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom + for super::SetSessionConfigOptionResponse + { + type Error = super::error::ConversionError; + fn try_from( + value: SetSessionConfigOptionResponse, + ) -> ::std::result::Result { + Ok(Self { + config_options: value.config_options?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From + for SetSessionConfigOptionResponse + { + fn from(value: super::SetSessionConfigOptionResponse) -> Self { + Self { + config_options: Ok(value.config_options), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct SetSessionModeRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + mode_id: ::std::result::Result, + session_id: ::std::result::Result, + } + impl ::std::default::Default for SetSessionModeRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + mode_id: Err("no value supplied for mode_id".to_string()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl SetSessionModeRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn mode_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.mode_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for mode_id: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SetSessionModeRequest { + type Error = super::error::ConversionError; + fn try_from( + value: SetSessionModeRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + mode_id: value.mode_id?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for SetSessionModeRequest { + fn from(value: super::SetSessionModeRequest) -> Self { + Self { + meta: Ok(value.meta), + mode_id: Ok(value.mode_id), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct SetSessionModeResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for SetSessionModeResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl SetSessionModeResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::SetSessionModeResponse { + type Error = super::error::ConversionError; + fn try_from( + value: SetSessionModeResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for SetSessionModeResponse { + fn from(value: super::SetSessionModeResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct Terminal { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + terminal_id: ::std::result::Result, + } + impl ::std::default::Default for Terminal { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + terminal_id: Err("no value supplied for terminal_id".to_string()), + } + } + } + impl Terminal { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn terminal_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::Terminal { + type Error = super::error::ConversionError; + fn try_from(value: Terminal) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + terminal_id: value.terminal_id?, + }) + } + } + impl ::std::convert::From for Terminal { + fn from(value: super::Terminal) -> Self { + Self { + meta: Ok(value.meta), + terminal_id: Ok(value.terminal_id), + } + } + } + #[derive(Clone, Debug)] + pub struct TerminalExitStatus { + exit_code: ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + signal: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for TerminalExitStatus { + fn default() -> Self { + Self { + exit_code: Ok(Default::default()), + meta: Ok(Default::default()), + signal: Ok(Default::default()), + } + } + } + impl TerminalExitStatus { + pub fn exit_code(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.exit_code = value + .try_into() + .map_err(|e| format!("error converting supplied value for exit_code: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn signal(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.signal = value + .try_into() + .map_err(|e| format!("error converting supplied value for signal: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::TerminalExitStatus { + type Error = super::error::ConversionError; + fn try_from( + value: TerminalExitStatus, + ) -> ::std::result::Result { + Ok(Self { + exit_code: value.exit_code?, + meta: value.meta?, + signal: value.signal?, + }) + } + } + impl ::std::convert::From for TerminalExitStatus { + fn from(value: super::TerminalExitStatus) -> Self { + Self { + exit_code: Ok(value.exit_code), + meta: Ok(value.meta), + signal: Ok(value.signal), + } + } + } + #[derive(Clone, Debug)] + pub struct TerminalOutputRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + terminal_id: ::std::result::Result, + } + impl ::std::default::Default for TerminalOutputRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + terminal_id: Err("no value supplied for terminal_id".to_string()), + } + } + } + impl TerminalOutputRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn terminal_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::TerminalOutputRequest { + type Error = super::error::ConversionError; + fn try_from( + value: TerminalOutputRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + terminal_id: value.terminal_id?, + }) + } + } + impl ::std::convert::From for TerminalOutputRequest { + fn from(value: super::TerminalOutputRequest) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + terminal_id: Ok(value.terminal_id), + } + } + } + #[derive(Clone, Debug)] + pub struct TerminalOutputResponse { + exit_status: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + output: ::std::result::Result<::std::string::String, ::std::string::String>, + truncated: ::std::result::Result, + } + impl ::std::default::Default for TerminalOutputResponse { + fn default() -> Self { + Self { + exit_status: Ok(Default::default()), + meta: Ok(Default::default()), + output: Err("no value supplied for output".to_string()), + truncated: Err("no value supplied for truncated".to_string()), + } + } + } + impl TerminalOutputResponse { + pub fn exit_status(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.exit_status = value + .try_into() + .map_err(|e| format!("error converting supplied value for exit_status: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn output(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.output = value + .try_into() + .map_err(|e| format!("error converting supplied value for output: {e}")); + self + } + pub fn truncated(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.truncated = value + .try_into() + .map_err(|e| format!("error converting supplied value for truncated: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::TerminalOutputResponse { + type Error = super::error::ConversionError; + fn try_from( + value: TerminalOutputResponse, + ) -> ::std::result::Result { + Ok(Self { + exit_status: value.exit_status?, + meta: value.meta?, + output: value.output?, + truncated: value.truncated?, + }) + } + } + impl ::std::convert::From for TerminalOutputResponse { + fn from(value: super::TerminalOutputResponse) -> Self { + Self { + exit_status: Ok(value.exit_status), + meta: Ok(value.meta), + output: Ok(value.output), + truncated: Ok(value.truncated), + } + } + } + #[derive(Clone, Debug)] + pub struct TextContent { + annotations: + ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + text: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for TextContent { + fn default() -> Self { + Self { + annotations: Ok(Default::default()), + meta: Ok(Default::default()), + text: Err("no value supplied for text".to_string()), + } + } + } + impl TextContent { + pub fn annotations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.annotations = value + .try_into() + .map_err(|e| format!("error converting supplied value for annotations: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn text(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.text = value + .try_into() + .map_err(|e| format!("error converting supplied value for text: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::TextContent { + type Error = super::error::ConversionError; + fn try_from( + value: TextContent, + ) -> ::std::result::Result { + Ok(Self { + annotations: value.annotations?, + meta: value.meta?, + text: value.text?, + }) + } + } + impl ::std::convert::From for TextContent { + fn from(value: super::TextContent) -> Self { + Self { + annotations: Ok(value.annotations), + meta: Ok(value.meta), + text: Ok(value.text), + } + } + } + #[derive(Clone, Debug)] + pub struct TextResourceContents { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + mime_type: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + text: ::std::result::Result<::std::string::String, ::std::string::String>, + uri: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for TextResourceContents { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + mime_type: Ok(Default::default()), + text: Err("no value supplied for text".to_string()), + uri: Err("no value supplied for uri".to_string()), + } + } + } + impl TextResourceContents { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn mime_type(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.mime_type = value + .try_into() + .map_err(|e| format!("error converting supplied value for mime_type: {e}")); + self + } + pub fn text(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.text = value + .try_into() + .map_err(|e| format!("error converting supplied value for text: {e}")); + self + } + pub fn uri(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.uri = value + .try_into() + .map_err(|e| format!("error converting supplied value for uri: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::TextResourceContents { + type Error = super::error::ConversionError; + fn try_from( + value: TextResourceContents, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + mime_type: value.mime_type?, + text: value.text?, + uri: value.uri?, + }) + } + } + impl ::std::convert::From for TextResourceContents { + fn from(value: super::TextResourceContents) -> Self { + Self { + meta: Ok(value.meta), + mime_type: Ok(value.mime_type), + text: Ok(value.text), + uri: Ok(value.uri), + } + } + } + #[derive(Clone, Debug)] + pub struct ToolCall { + content: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + kind: ::std::result::Result<::std::option::Option, ::std::string::String>, + locations: + ::std::result::Result<::std::vec::Vec, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + raw_input: ::std::result::Result< + ::std::option::Option<::serde_json::Value>, + ::std::string::String, + >, + raw_output: ::std::result::Result< + ::std::option::Option<::serde_json::Value>, + ::std::string::String, + >, + status: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + title: ::std::result::Result<::std::string::String, ::std::string::String>, + tool_call_id: ::std::result::Result, + } + impl ::std::default::Default for ToolCall { + fn default() -> Self { + Self { + content: Ok(Default::default()), + kind: Ok(Default::default()), + locations: Ok(Default::default()), + meta: Ok(Default::default()), + raw_input: Ok(Default::default()), + raw_output: Ok(Default::default()), + status: Ok(Default::default()), + title: Err("no value supplied for title".to_string()), + tool_call_id: Err("no value supplied for tool_call_id".to_string()), + } + } + } + impl ToolCall { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn kind(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.kind = value + .try_into() + .map_err(|e| format!("error converting supplied value for kind: {e}")); + self + } + pub fn locations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::vec::Vec>, + T::Error: ::std::fmt::Display, + { + self.locations = value + .try_into() + .map_err(|e| format!("error converting supplied value for locations: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn raw_input(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::serde_json::Value>>, + T::Error: ::std::fmt::Display, + { + self.raw_input = value + .try_into() + .map_err(|e| format!("error converting supplied value for raw_input: {e}")); + self + } + pub fn raw_output(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::serde_json::Value>>, + T::Error: ::std::fmt::Display, + { + self.raw_output = value + .try_into() + .map_err(|e| format!("error converting supplied value for raw_output: {e}")); + self + } + pub fn status(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.status = value + .try_into() + .map_err(|e| format!("error converting supplied value for status: {e}")); + self + } + pub fn title(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.title = value + .try_into() + .map_err(|e| format!("error converting supplied value for title: {e}")); + self + } + pub fn tool_call_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.tool_call_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for tool_call_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ToolCall { + type Error = super::error::ConversionError; + fn try_from(value: ToolCall) -> ::std::result::Result { + Ok(Self { + content: value.content?, + kind: value.kind?, + locations: value.locations?, + meta: value.meta?, + raw_input: value.raw_input?, + raw_output: value.raw_output?, + status: value.status?, + title: value.title?, + tool_call_id: value.tool_call_id?, + }) + } + } + impl ::std::convert::From for ToolCall { + fn from(value: super::ToolCall) -> Self { + Self { + content: Ok(value.content), + kind: Ok(value.kind), + locations: Ok(value.locations), + meta: Ok(value.meta), + raw_input: Ok(value.raw_input), + raw_output: Ok(value.raw_output), + status: Ok(value.status), + title: Ok(value.title), + tool_call_id: Ok(value.tool_call_id), + } + } + } + #[derive(Clone, Debug)] + pub struct ToolCallLocation { + line: ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + path: ::std::result::Result<::std::string::String, ::std::string::String>, + } + impl ::std::default::Default for ToolCallLocation { + fn default() -> Self { + Self { + line: Ok(Default::default()), + meta: Ok(Default::default()), + path: Err("no value supplied for path".to_string()), + } + } + } + impl ToolCallLocation { + pub fn line(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.line = value + .try_into() + .map_err(|e| format!("error converting supplied value for line: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn path(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.path = value + .try_into() + .map_err(|e| format!("error converting supplied value for path: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ToolCallLocation { + type Error = super::error::ConversionError; + fn try_from( + value: ToolCallLocation, + ) -> ::std::result::Result { + Ok(Self { + line: value.line?, + meta: value.meta?, + path: value.path?, + }) + } + } + impl ::std::convert::From for ToolCallLocation { + fn from(value: super::ToolCallLocation) -> Self { + Self { + line: Ok(value.line), + meta: Ok(value.meta), + path: Ok(value.path), + } + } + } + #[derive(Clone, Debug)] + pub struct ToolCallUpdate { + content: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + kind: ::std::result::Result<::std::option::Option, ::std::string::String>, + locations: ::std::result::Result< + ::std::option::Option<::std::vec::Vec>, + ::std::string::String, + >, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + raw_input: ::std::result::Result< + ::std::option::Option<::serde_json::Value>, + ::std::string::String, + >, + raw_output: ::std::result::Result< + ::std::option::Option<::serde_json::Value>, + ::std::string::String, + >, + status: ::std::result::Result< + ::std::option::Option, + ::std::string::String, + >, + title: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + tool_call_id: ::std::result::Result, + } + impl ::std::default::Default for ToolCallUpdate { + fn default() -> Self { + Self { + content: Ok(Default::default()), + kind: Ok(Default::default()), + locations: Ok(Default::default()), + meta: Ok(Default::default()), + raw_input: Ok(Default::default()), + raw_output: Ok(Default::default()), + status: Ok(Default::default()), + title: Ok(Default::default()), + tool_call_id: Err("no value supplied for tool_call_id".to_string()), + } + } + } + impl ToolCallUpdate { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn kind(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.kind = value + .try_into() + .map_err(|e| format!("error converting supplied value for kind: {e}")); + self + } + pub fn locations(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option<::std::vec::Vec>, + >, + T::Error: ::std::fmt::Display, + { + self.locations = value + .try_into() + .map_err(|e| format!("error converting supplied value for locations: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn raw_input(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::serde_json::Value>>, + T::Error: ::std::fmt::Display, + { + self.raw_input = value + .try_into() + .map_err(|e| format!("error converting supplied value for raw_input: {e}")); + self + } + pub fn raw_output(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::serde_json::Value>>, + T::Error: ::std::fmt::Display, + { + self.raw_output = value + .try_into() + .map_err(|e| format!("error converting supplied value for raw_output: {e}")); + self + } + pub fn status(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.status = value + .try_into() + .map_err(|e| format!("error converting supplied value for status: {e}")); + self + } + pub fn title(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.title = value + .try_into() + .map_err(|e| format!("error converting supplied value for title: {e}")); + self + } + pub fn tool_call_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.tool_call_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for tool_call_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::ToolCallUpdate { + type Error = super::error::ConversionError; + fn try_from( + value: ToolCallUpdate, + ) -> ::std::result::Result { + Ok(Self { + content: value.content?, + kind: value.kind?, + locations: value.locations?, + meta: value.meta?, + raw_input: value.raw_input?, + raw_output: value.raw_output?, + status: value.status?, + title: value.title?, + tool_call_id: value.tool_call_id?, + }) + } + } + impl ::std::convert::From for ToolCallUpdate { + fn from(value: super::ToolCallUpdate) -> Self { + Self { + content: Ok(value.content), + kind: Ok(value.kind), + locations: Ok(value.locations), + meta: Ok(value.meta), + raw_input: Ok(value.raw_input), + raw_output: Ok(value.raw_output), + status: Ok(value.status), + title: Ok(value.title), + tool_call_id: Ok(value.tool_call_id), + } + } + } + #[derive(Clone, Debug)] + pub struct UnstructuredCommandInput { + hint: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for UnstructuredCommandInput { + fn default() -> Self { + Self { + hint: Err("no value supplied for hint".to_string()), + meta: Ok(Default::default()), + } + } + } + impl UnstructuredCommandInput { + pub fn hint(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.hint = value + .try_into() + .map_err(|e| format!("error converting supplied value for hint: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::UnstructuredCommandInput { + type Error = super::error::ConversionError; + fn try_from( + value: UnstructuredCommandInput, + ) -> ::std::result::Result { + Ok(Self { + hint: value.hint?, + meta: value.meta?, + }) + } + } + impl ::std::convert::From for UnstructuredCommandInput { + fn from(value: super::UnstructuredCommandInput) -> Self { + Self { + hint: Ok(value.hint), + meta: Ok(value.meta), + } + } + } + #[derive(Clone, Debug)] + pub struct UsageUpdate { + cost: ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + size: ::std::result::Result, + used: ::std::result::Result, + } + impl ::std::default::Default for UsageUpdate { + fn default() -> Self { + Self { + cost: Ok(Default::default()), + meta: Ok(Default::default()), + size: Err("no value supplied for size".to_string()), + used: Err("no value supplied for used".to_string()), + } + } + } + impl UsageUpdate { + pub fn cost(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.cost = value + .try_into() + .map_err(|e| format!("error converting supplied value for cost: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn size(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.size = value + .try_into() + .map_err(|e| format!("error converting supplied value for size: {e}")); + self + } + pub fn used(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.used = value + .try_into() + .map_err(|e| format!("error converting supplied value for used: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::UsageUpdate { + type Error = super::error::ConversionError; + fn try_from( + value: UsageUpdate, + ) -> ::std::result::Result { + Ok(Self { + cost: value.cost?, + meta: value.meta?, + size: value.size?, + used: value.used?, + }) + } + } + impl ::std::convert::From for UsageUpdate { + fn from(value: super::UsageUpdate) -> Self { + Self { + cost: Ok(value.cost), + meta: Ok(value.meta), + size: Ok(value.size), + used: Ok(value.used), + } + } + } + #[derive(Clone, Debug)] + pub struct WaitForTerminalExitRequest { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + session_id: ::std::result::Result, + terminal_id: ::std::result::Result, + } + impl ::std::default::Default for WaitForTerminalExitRequest { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + session_id: Err("no value supplied for session_id".to_string()), + terminal_id: Err("no value supplied for terminal_id".to_string()), + } + } + } + impl WaitForTerminalExitRequest { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + pub fn terminal_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.terminal_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for terminal_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::WaitForTerminalExitRequest { + type Error = super::error::ConversionError; + fn try_from( + value: WaitForTerminalExitRequest, + ) -> ::std::result::Result { + Ok(Self { + meta: value.meta?, + session_id: value.session_id?, + terminal_id: value.terminal_id?, + }) + } + } + impl ::std::convert::From for WaitForTerminalExitRequest { + fn from(value: super::WaitForTerminalExitRequest) -> Self { + Self { + meta: Ok(value.meta), + session_id: Ok(value.session_id), + terminal_id: Ok(value.terminal_id), + } + } + } + #[derive(Clone, Debug)] + pub struct WaitForTerminalExitResponse { + exit_code: ::std::result::Result<::std::option::Option, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + signal: ::std::result::Result< + ::std::option::Option<::std::string::String>, + ::std::string::String, + >, + } + impl ::std::default::Default for WaitForTerminalExitResponse { + fn default() -> Self { + Self { + exit_code: Ok(Default::default()), + meta: Ok(Default::default()), + signal: Ok(Default::default()), + } + } + } + impl WaitForTerminalExitResponse { + pub fn exit_code(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option>, + T::Error: ::std::fmt::Display, + { + self.exit_code = value + .try_into() + .map_err(|e| format!("error converting supplied value for exit_code: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn signal(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::option::Option<::std::string::String>>, + T::Error: ::std::fmt::Display, + { + self.signal = value + .try_into() + .map_err(|e| format!("error converting supplied value for signal: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::WaitForTerminalExitResponse { + type Error = super::error::ConversionError; + fn try_from( + value: WaitForTerminalExitResponse, + ) -> ::std::result::Result { + Ok(Self { + exit_code: value.exit_code?, + meta: value.meta?, + signal: value.signal?, + }) + } + } + impl ::std::convert::From for WaitForTerminalExitResponse { + fn from(value: super::WaitForTerminalExitResponse) -> Self { + Self { + exit_code: Ok(value.exit_code), + meta: Ok(value.meta), + signal: Ok(value.signal), + } + } + } + #[derive(Clone, Debug)] + pub struct WriteTextFileRequest { + content: ::std::result::Result<::std::string::String, ::std::string::String>, + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + path: ::std::result::Result<::std::string::String, ::std::string::String>, + session_id: ::std::result::Result, + } + impl ::std::default::Default for WriteTextFileRequest { + fn default() -> Self { + Self { + content: Err("no value supplied for content".to_string()), + meta: Ok(Default::default()), + path: Err("no value supplied for path".to_string()), + session_id: Err("no value supplied for session_id".to_string()), + } + } + } + impl WriteTextFileRequest { + pub fn content(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.content = value + .try_into() + .map_err(|e| format!("error converting supplied value for content: {e}")); + self + } + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + pub fn path(mut self, value: T) -> Self + where + T: ::std::convert::TryInto<::std::string::String>, + T::Error: ::std::fmt::Display, + { + self.path = value + .try_into() + .map_err(|e| format!("error converting supplied value for path: {e}")); + self + } + pub fn session_id(mut self, value: T) -> Self + where + T: ::std::convert::TryInto, + T::Error: ::std::fmt::Display, + { + self.session_id = value + .try_into() + .map_err(|e| format!("error converting supplied value for session_id: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::WriteTextFileRequest { + type Error = super::error::ConversionError; + fn try_from( + value: WriteTextFileRequest, + ) -> ::std::result::Result { + Ok(Self { + content: value.content?, + meta: value.meta?, + path: value.path?, + session_id: value.session_id?, + }) + } + } + impl ::std::convert::From for WriteTextFileRequest { + fn from(value: super::WriteTextFileRequest) -> Self { + Self { + content: Ok(value.content), + meta: Ok(value.meta), + path: Ok(value.path), + session_id: Ok(value.session_id), + } + } + } + #[derive(Clone, Debug)] + pub struct WriteTextFileResponse { + meta: ::std::result::Result< + ::std::option::Option<::serde_json::Map<::std::string::String, ::serde_json::Value>>, + ::std::string::String, + >, + } + impl ::std::default::Default for WriteTextFileResponse { + fn default() -> Self { + Self { + meta: Ok(Default::default()), + } + } + } + impl WriteTextFileResponse { + pub fn meta(mut self, value: T) -> Self + where + T: ::std::convert::TryInto< + ::std::option::Option< + ::serde_json::Map<::std::string::String, ::serde_json::Value>, + >, + >, + T::Error: ::std::fmt::Display, + { + self.meta = value + .try_into() + .map_err(|e| format!("error converting supplied value for meta: {e}")); + self + } + } + impl ::std::convert::TryFrom for super::WriteTextFileResponse { + type Error = super::error::ConversionError; + fn try_from( + value: WriteTextFileResponse, + ) -> ::std::result::Result { + Ok(Self { meta: value.meta? }) + } + } + impl ::std::convert::From for WriteTextFileResponse { + fn from(value: super::WriteTextFileResponse) -> Self { + Self { + meta: Ok(value.meta), + } + } + } +} +#[doc = r" Generation of default values for serde."] +pub mod defaults { + pub(super) fn agent_capabilities_auth() -> super::AgentAuthCapabilities { + super::AgentAuthCapabilities { + logout: Default::default(), + meta: Default::default(), + } + } + pub(super) fn agent_capabilities_mcp_capabilities() -> super::McpCapabilities { + super::McpCapabilities { + http: false, + meta: Default::default(), + sse: false, + } + } + pub(super) fn agent_capabilities_prompt_capabilities() -> super::PromptCapabilities { + super::PromptCapabilities { + audio: false, + embedded_context: false, + image: false, + meta: Default::default(), + } + } + pub(super) fn agent_capabilities_session_capabilities() -> super::SessionCapabilities { + super::SessionCapabilities { + additional_directories: Default::default(), + close: Default::default(), + delete: Default::default(), + list: Default::default(), + meta: Default::default(), + resume: Default::default(), + } + } + pub(super) fn client_capabilities_fs() -> super::FileSystemCapabilities { + super::FileSystemCapabilities { + meta: Default::default(), + read_text_file: false, + write_text_file: false, + } + } + pub(super) fn initialize_request_client_capabilities() -> super::ClientCapabilities { + super::ClientCapabilities { + fs: super::FileSystemCapabilities { + meta: Default::default(), + read_text_file: false, + write_text_file: false, + }, + meta: Default::default(), + session: Default::default(), + terminal: false, + } + } + pub(super) fn initialize_response_agent_capabilities() -> super::AgentCapabilities { + super::AgentCapabilities { + auth: super::AgentAuthCapabilities { + logout: Default::default(), + meta: Default::default(), + }, + load_session: false, + mcp_capabilities: super::McpCapabilities { + http: false, + meta: Default::default(), + sse: false, + }, + meta: Default::default(), + prompt_capabilities: super::PromptCapabilities { + audio: false, + embedded_context: false, + image: false, + meta: Default::default(), + }, + session_capabilities: super::SessionCapabilities { + additional_directories: Default::default(), + close: Default::default(), + delete: Default::default(), + list: Default::default(), + meta: Default::default(), + resume: Default::default(), + }, + } + } +} diff --git a/crates/openab-gateway/src/adapters/mod.rs b/crates/openab-gateway/src/adapters/mod.rs index ac7867766..1933e6c05 100644 --- a/crates/openab-gateway/src/adapters/mod.rs +++ b/crates/openab-gateway/src/adapters/mod.rs @@ -14,3 +14,6 @@ pub mod wecom; pub mod teams; #[cfg(feature = "acp")] pub mod acp_server; +#[cfg(feature = "acp")] +#[allow(clippy::all, dead_code, unused)] +pub mod acp_schema; From df4406abc8cb99ab041942fae369d5ea31f9ecba Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 15:36:27 +0800 Subject: [PATCH 12/49] test(acp): conformance guard pinning hand-rolled wire to generated types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add acp_conformance test module: every payload acp_server hand-rolls (initialize / session.new / resume / prompt stopReason / session.update agent_message_chunk) and accepts (prompt request) is asserted to deserialize into the generated acp_schema ACP v1 types, with serde proven a stable fixed point. Any casing / field-name / shape drift — the class of bug fixed during the base build (agentMessageChunk->agent_message_chunk, integer protocolVersion, snake_case stopReason) — now fails CI. Per ADR §7 the trivial chat payloads stay hand-rolled; this guard locks them to the schema. Typed construction for the complex bidirectional/MCP surface is the roadmap's job. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 46dc83be0..244e820c4 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -761,3 +761,90 @@ pub async fn handle_reply(reply: &GatewayReply, registry: &AcpReplyRegistry) { _ => {} } } + +// --------------------------------------------------------------------------- +// Conformance guard — the wire this server hand-rolls MUST validate against the +// generated ACP v1 types (`acp_schema`). Any casing / field-name / shape drift +// (the exact class of bug fixed during the base build: `agentMessageChunk` → +// `agent_message_chunk`, integer `protocolVersion`, snake_case `stopReason`) +// fails these tests. Also pins the generated types as the schema source of truth +// while the payloads stay hand-rolled (per ADR §7: hand-roll the trivial chat +// subset, generate the complex bidirectional surface). +// --------------------------------------------------------------------------- +#[cfg(test)] +mod acp_conformance { + use crate::adapters::acp_schema as sc; + use serde_json::{json, Value}; + + /// Assert `wire` (a payload this server emits or accepts) deserializes into the + /// generated ACP type `T`, and that `T`'s serde is a stable fixed point + /// (serialize→deserialize→serialize is idempotent). No `PartialEq` needed on `T`. + fn conforms(wire: Value) + where + T: serde::Serialize + serde::de::DeserializeOwned, + { + let a: T = serde_json::from_value(wire.clone()) + .unwrap_or_else(|e| panic!("emitted wire is not valid ACP {}: {e}\n wire={wire}", std::any::type_name::())); + let v1 = serde_json::to_value(&a).unwrap(); + let b: T = serde_json::from_value(v1.clone()).expect("re-parse of generated form"); + let v2 = serde_json::to_value(&b).unwrap(); + assert_eq!(v1, v2, "ACP serde is not a stable fixed point for {}", std::any::type_name::()); + } + + // --- outbound responses (exact shapes handle_* emit) --- + + #[test] + fn initialize_response() { + // mirror of handle_initialize + conforms::(json!({ + "protocolVersion": 1, + "agentCapabilities": { + "loadSession": false, + "sessionCapabilities": { "resume": {} }, + "promptCapabilities": { "image": false, "audio": false, "embeddedContext": false } + }, + "agentInfo": { "name": "openab", "title": "OpenAB", "version": "0.0.0" }, + "authMethods": [] + })); + } + + #[test] + fn new_session_response() { + conforms::(json!({ "sessionId": "sess_00000000-0000-0000-0000-000000000000" })); + } + + #[test] + fn resume_session_response() { + // handle_session_resume returns {} + conforms::(json!({})); + } + + #[test] + fn prompt_response_stop_reasons() { + // handle_prompt emits end_turn (normal) / cancelled (session/cancel) + conforms::(json!({ "stopReason": "end_turn" })); + conforms::(json!({ "stopReason": "cancelled" })); + } + + #[test] + fn session_update_agent_message_chunk() { + // the streaming notification `params` (session/update) + conforms::(json!({ + "sessionId": "sess_00000000-0000-0000-0000-000000000000", + "update": { + "sessionUpdate": "agent_message_chunk", + "content": { "type": "text", "text": "PONG 你好 (๑•̀ㅂ•́)و" } + } + })); + } + + // --- inbound requests (params clients send) --- + + #[test] + fn prompt_request() { + conforms::(json!({ + "sessionId": "sess_00000000-0000-0000-0000-000000000000", + "prompt": [{ "type": "text", "text": "PING" }] + })); + } +} From 455164c1fdaed9e799e8f69e20592583537df478 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 15:48:53 +0800 Subject: [PATCH 13/49] =?UTF-8?q?docs(acp):=20update=20base=20ADR=20=C2=A7?= =?UTF-8?q?7=20to=20as-built=20(generated=20types=20shipped=20+=20conforma?= =?UTF-8?q?nce-pinned)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §7 now records what shipped: acp_schema.rs generated + committed (typify 0.7.0, serde-only, schema vendored/pinned to v1.19.0), trivial chat payloads kept hand-rolled per the rule, and the acp_conformance test pinning them to the generated types as the round-trip validation. Full typed construction migration is documented as deferred to the bidirectional/MCP roadmap. Doc-only. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 52 ++++++++++++++++++++------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 5223f4a94..d74a7faa3 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -175,14 +175,36 @@ North star: the agent's LLM autonomously operating the user's real browser (gene reveals the variant surface downstream agents actually emit, informs which of the Optional variants to forward, and validates the generated-type round-trip. -## 7. Typing & dependency decision (hand-rolled now → generated later) - -Both sides of OpenAB's ACP are currently **hand-rolled, untyped** (`serde_json::Value` + -manual string matching on `sessionUpdate` variants): the upstream server here (~740 -lines, chat only) and the downstream client in `openab-core/src/acp/` (`protocol.rs` + -`connection.rs`, ~1800 lines, many variants). Hand-rolling caused the exact conformance -bugs fixed during the base build (`agentMessageChunk`→`agent_message_chunk`, `stopReason` -snake_case, integer `protocolVersion: 1`). +## 7. Typing & dependency decision (as-built: generated types vendored; trivial payloads hand-rolled + conformance-pinned) + +Both sides of OpenAB's ACP started **hand-rolled, untyped** (`serde_json::Value` + manual +string matching on `sessionUpdate` variants): the upstream server here (~740 lines, chat +only) and the downstream client in `openab-core/src/acp/` (`protocol.rs` + `connection.rs`, +~1800 lines, many variants). Hand-rolling caused the exact conformance bugs fixed during the +base build (`agentMessageChunk`→`agent_message_chunk`, `stopReason` snake_case, integer +`protocolVersion: 1`). + +**As-built (this PR).** The generated types now exist and are committed, but the switch was +made surgically per the rule below rather than as a blanket rewrite: + +- **Generated types vendored + committed** — `crates/openab-gateway/src/adapters/acp_schema.rs` + (feature-gated `acp`), produced by `cargo-typify 0.7.0` from the vendored ACP v1 schema + (`crates/openab-gateway/schemas/acp-v1.schema.json`, pinned to upstream `schema.json` + @ `eb88e992` / ACP Schema v1.19.0). Plain serde, **0** `schemars`/`serde_with` in the + generated body (verified). The full v1 surface is generated (one closed dep graph — a + hand-trimmed subset would not be meaningfully smaller and would diverge from the schema); + the remainder beyond the chat subset is inert `dead_code` until the roadmap consumes it. +- **Trivial chat payloads stay hand-rolled** (`json!`) — they are correct and readable, and + the typify construction ergonomics for them are poor (`AgentCapabilities` has no `Default`; + `ContentBlock` is an untagged `VariantN`). Per the rule, we did **not** churn them into + builder chains. +- **Conformance is pinned, not asserted by construction** — the `acp_conformance` test module + in `acp_server.rs` deserializes every hand-rolled payload the server emits/accepts through + the generated types and proves serde is a stable fixed point. Any casing/field/shape drift + (the original bug class) now fails CI. This is the round-trip validation §6 called for. +- **Full typed *construction* migration is deferred** to the bidirectional / MCP-over-ACP + surface (roadmap §6 Critical path), where hand-rolling actually breaks and the generated + types earn their keep. The trivial base does not need it. Options weighed for typing the wire: @@ -191,15 +213,19 @@ Options weighed for typing the wire: | Hand-roll (current) | 0 | Fine for the trivial chat subset; error-prone for the big bidirectional surface | | Full `agent-client-protocol` crate | ~105 (incl. a 2nd async runtime, async-io/smol) | **Never** — connection/role machinery unneeded (we have our own WS + GatewayEvent bridge) | | `agent-client-protocol-schema` (types) | **+24** (measured 376→400), schemars-dominated | schemars is for `JsonSchema` derive we don't use at runtime; `serde_with`/`strum` mandatory (no feature to drop); floor is fixed | -| **Offline codegen (typify) → committed serde-only `.rs`** | **~0 runtime** | **Chosen for the expanded surface** — typed conformance without the schemars tree | +| **Offline codegen (typify) → committed serde-only `.rs`** | **~0 runtime** | **Chosen & shipped** — `acp_schema.rs` generated + committed; typed conformance without the schemars tree | Notes: - **v1 only.** `v2` is experimental (`unstable_protocol_v2`, adds `diffy`), currently wire-identical to v1, "may change at any time". We negotiate `protocolVersion 1`. -- **Caveat:** ACP types lean on `serde_with` (MaybeUndefined tri-state, ~600 uses across - the crate's v1 source) — so a naive vendor-and-strip-`JsonSchema` is not clean, and - typify's plain-serde output must be **round-trip validated** (simple chat fields are - fine; advanced patterns need checking — hence the ACP trace mode in §6). +- **Caveat (resolved for the chat subset):** ACP types lean on `serde_with` (MaybeUndefined + tri-state, ~600 uses across the crate's v1 source), so a naive vendor-and-strip-`JsonSchema` + is not clean and typify's plain-serde output must be **round-trip validated**. For the chat + subset this is now **done** — the PoC and the `acp_conformance` test show the generated types + round-trip the real wire exactly, with **no** `serde_with`/MaybeUndefined divergence (the one + nuance: typify materializes schema-default capability booleans explicitly, which is + semantically identical). Advanced bidirectional variants still warrant the same check via the + §6 ACP trace mode before they are wired. - **Rule:** hand-roll only the trivial; **generate the complex.** The switch point is the bidirectional/MCP surface. Highest ROI if unifying: the downstream core client (~1800 lines of manual variant matching), not this small upstream server. From 99d3c59d6a09fcb9fc451877e28a7fa9c1badcf9 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 16:02:57 +0800 Subject: [PATCH 14/49] =?UTF-8?q?docs(acp):=20record=20cwd=20non-propagati?= =?UTF-8?q?on=20as=20a=20deliberate=20security=20decision=20(=C2=A75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Investigation for the "propagate cwd" item found the downstream plumbing already exists (openab-core pool working_dir_override) but is sourced only via the [[ws:…]] directive, resolved by resolve_workspace which contains every path under bot_home. Honoring a raw client cwd as current_dir would bypass that containment — unsafe for a default-unauthenticated endpoint, and meaningless for the base's browser client (no valid pod-side path). §5 now documents this as a deliberate decision and records the safe wiring (route cwd through resolve_workspace) for when an authenticated IDE-style client actually needs it. Doc-only. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index d74a7faa3..c1b7cdae0 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -130,7 +130,18 @@ and rejecting forged ids. includes them in a prompt — no ACP-specific work required. A typed UI for them (`authenticate` / `available_commands_update`) is an optional later nicety. - **cwd / mcpServers** — accepted on `session/new` / `session/resume` for wire - conformance but not yet propagated into the agent (follow-up). + conformance but **deliberately not propagated** into the agent working dir in the base. + This is a security decision, not just a TODO: the downstream plumbing already exists + (`openab-core` `pool.get_or_create(working_dir_override)`), but its only source is the + `[[ws:…]]` message-text directive, resolved by `resolve_workspace` which **contains every + path under the bot's home** (`canonical_target.starts_with(bot_home)`, must exist, must be + a dir). Honoring a raw client-supplied `cwd` as the process `current_dir` would bypass that + containment — unacceptable for an endpoint that is **unauthenticated by default** (§2). And + for the base's real clients (a browser side-panel) `cwd` is meaningless: they don't know a + valid pod-side path under `bot_home`, so it would fall back to the config default anyway. + When it is actually wanted (an authenticated IDE-style client), the safe wiring is to route + the ACP `cwd` **through** the same `resolve_workspace` containment (arbitrary paths rejected, + only existing dirs under `bot_home` honored) — not straight into `current_dir`. - **Emoji** — inline 顏文字 flow through as text; reaction emoji stay no-op in the base. - **Reconnect** — on WS disconnect the per-connection session map is dropped; the client reconnects with `session/resume` + its persisted `sessionId`. From 0b048380ef9d4383aa82ad88272b221378a32e55 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 16:17:30 +0800 Subject: [PATCH 15/49] =?UTF-8?q?docs(acp):=20record=20command-parity=20ve?= =?UTF-8?q?rification=20by=20construction=20(=C2=A75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Traced the command path for the "verify openab commands over ACP" item: directives (parse_directives in dispatch.rs) and slash commands (/reset, /model in process_gateway_event + run_gateway_adapter) are platform-agnostic and keyed on event.platform generically — nothing special-cases acp out, and interception reads event.content.text (the ACP prompt text). §5 upgraded from assertion to verified-by- construction. Remaining runtime item (does a slash reply render back into the ACP stream) folds into the deploy-gated e2e. Doc-only. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index c1b7cdae0..68076fa79 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -127,8 +127,15 @@ and rejecting forged ids. - **OpenAB command parity is mostly free** — control directives (`[[ws]]`, `[[model]]`, …) and slash commands (`/reset`, `/model`, …) are message-text conventions parsed platform-agnostically (`openab-core`), so they already work over ACP when the client - includes them in a prompt — no ACP-specific work required. A typed UI for them - (`authenticate` / `available_commands_update`) is an optional later nicety. + includes them in a prompt — no ACP-specific work required. **Verified by construction:** + directives go through `directives::parse_directives` in `dispatch.rs` (no platform gating); + `/reset` and `/model` are intercepted in `process_gateway_event` (and the `run_gateway_adapter` + path), both keyed on `event.platform` generically — nothing special-cases `acp` out, and the + interception reads `event.content.text`, which for ACP is the prompt text the client sends. + The one runtime item left to confirm on a live agent is whether a slash command's + *confirmation* reply (`send_fire_and_forget`) renders back into the ACP client's stream — + folded into the deploy-gated e2e re-verify. A typed UI for them (`authenticate` / + `available_commands_update`) is an optional later nicety. - **cwd / mcpServers** — accepted on `session/new` / `session/resume` for wire conformance but **deliberately not propagated** into the agent working dir in the base. This is a security decision, not just a TODO: the downstream plumbing already exists From 97059880489b5a82f710288a31259807d6c55145 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 17:07:51 +0800 Subject: [PATCH 16/49] test(acp): add WebSocket /acp e2e smoke script + wire into canary-tests scripts/acp-ws-smoke.py: a uv-runnable ACP-over-WebSocket client for the upstream client<->gateway /acp hop (distinct from the downstream stdio hop in Layer 2). Drives initialize -> session/new -> session/prompt (stream + stopReason) -> session/resume, and confirms /model and /reset slash-command replies render back over ACP as agent_message_chunk. Parameterized WS URL + optional OPENAB_ACP_TOKEN; exits non-zero unless all 7 checks pass. Verified 7/7 against a live deployment. docs/canary-tests.md: new "WebSocket transport (/acp)" subsection under Layer 2 pointing at the script and cross-linking the offline acp_conformance cargo test. Co-Authored-By: Claude Opus 4.8 --- docs/canary-tests.md | 14 ++++ scripts/acp-ws-smoke.py | 156 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100755 scripts/acp-ws-smoke.py diff --git a/docs/canary-tests.md b/docs/canary-tests.md index 05cc0cc15..7656c5502 100644 --- a/docs/canary-tests.md +++ b/docs/canary-tests.md @@ -10,6 +10,7 @@ The goal is to produce evidence that another contributor or maintainer can revie - [Build the Preview Image](#build-the-preview-image) - [Layer 1: Image Inspection](#layer-1-image-inspection) - [Layer 2: ACP Protocol Smoke](#layer-2-acp-protocol-smoke) + - [WebSocket transport (`/acp`)](#websocket-transport-acp) - [Transport Method](#transport-method) - [Layer 3: Runtime Isolation Probe](#layer-3-runtime-isolation-probe) - [Layer 4: Interactive Validation](#layer-4-interactive-validation) @@ -147,6 +148,19 @@ Avoid printing the live container environment because it may include injected cr For an ACP adapter change, use a minimal bidirectional JSON-RPC client to exercise the same stdio boundary OpenAB uses. The client may be written in any language; JavaScript is not required. A one-way shell pipeline is insufficient for multi-turn and permission tests because the adapter can send requests back to the client while a prompt is running. +### WebSocket transport (`/acp`) + +OpenAB also serves ACP over a WebSocket (`GET /acp`, feature `acp` + `OPENAB_ACP_ENABLED`) — the upstream client↔gateway hop, distinct from the downstream stdio hop below. `scripts/acp-ws-smoke.py` is a ready-to-run client for it: it drives `initialize → session/new → session/prompt` (stream + `stopReason`) `→ session/resume`, and confirms OpenAB slash-command replies (`/model`, `/reset`) render back over ACP. It needs a live deployment (the prompt turns hit the real model). + +```bash +# default ws://localhost:8080/acp; pass another URL as $1 +uv run scripts/acp-ws-smoke.py ws://:8080/acp +# if the endpoint sets OPENAB_ACP_AUTH_KEY: +OPENAB_ACP_TOKEN= uv run scripts/acp-ws-smoke.py ws://:8080/acp +``` + +Exits non-zero unless all checks pass. For the in-repo `cargo test` counterpart (offline wire-conformance of the same payloads against the generated types), see the `acp_conformance` module in `crates/openab-gateway/src/adapters/acp_server.rs`. + ### Transport Method 1. Start the preview container with stdin open and the agent binary as its entrypoint. Mount only isolated test credentials and a disposable workspace. The bidirectional client should spawn an equivalent command rather than pipe a fixed list of messages into it. For the Codex preview image: diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py new file mode 100755 index 000000000..0704f32c4 --- /dev/null +++ b/scripts/acp-ws-smoke.py @@ -0,0 +1,156 @@ +#!/usr/bin/env -S uv run --quiet --script +# /// script +# requires-python = ">=3.11" +# dependencies = ["websockets>=12"] +# /// +""" +ACP-over-WebSocket smoke test — upstream client<->gateway `/acp` hop. + +This exercises the WebSocket ACP server this PR adds (GET /acp on the openab +gateway / embedded `openab run`), which is a different boundary from the +downstream core<->agent-CLI stdio hop covered by docs/canary-tests.md Layer 2. +It drives a real deployment end to end, so a live agent backend is required — +the prompt turns hit the actual model. + +Usage: + uv run scripts/acp-ws-smoke.py [WS_URL] + ACP_URL=ws://host:8080/acp uv run scripts/acp-ws-smoke.py + + # default WS_URL: ws://localhost:8080/acp + # if the endpoint sets OPENAB_ACP_AUTH_KEY, pass the token: + OPENAB_ACP_TOKEN= uv run scripts/acp-ws-smoke.py ws://host:8080/acp + +Checks (exit 0 iff all pass, else 2): + 1. initialize -> protocolVersion == 1 and agentCapabilities present + 2. session/new -> { sessionId: sess_... } + 3. session/prompt -> agent_message_chunk stream is non-empty + 4. session/prompt -> response stopReason == "end_turn" + 5. session/resume -> {} (no error, no history replay) + 6. "/model" as a prompt -> the config-command reply renders back over ACP + 7. "/reset" as a prompt -> the session-command reply renders back over ACP + +Checks 6-7 confirm OpenAB slash-command replies reach the ACP client stream +(they arrive as agent_message_chunk), i.e. command parity over ACP. +""" +import asyncio +import json +import os +import sys + +import websockets + + +def build_url() -> str: + url = sys.argv[1] if len(sys.argv) > 1 else os.environ.get("ACP_URL", "ws://localhost:8080/acp") + token = os.environ.get("OPENAB_ACP_TOKEN") + if token: + sep = "&" if "?" in url else "?" + url = f"{url}{sep}token={token}" + return url + + +results: list[tuple[bool, str]] = [] + + +def check(ok: bool, name: str, detail: str = "") -> None: + results.append((ok, name)) + mark = "PASS" if ok else "FAIL" + print(f" [{mark}] {name}{(' — ' + detail) if detail else ''}", flush=True) + + +async def main() -> int: + url = build_url() + redacted = url.split("token=")[0] + "token=" if "token=" in url else url + print(f"ACP WS smoke → {redacted}", flush=True) + + async with websockets.connect(url, open_timeout=8, max_size=None) as ws: + next_id = 0 + + async def call(method, params=None, timeout=8): + """Send a JSON-RPC request; collect streamed notifications until the + response with the matching id arrives (or timeout).""" + nonlocal next_id + next_id += 1 + req_id = next_id + msg = {"jsonrpc": "2.0", "id": req_id, "method": method} + if params is not None: + msg["params"] = params + await ws.send(json.dumps(msg)) + chunks: list[str] = [] + notifs: list[str] = [] + while True: + try: + raw = await asyncio.wait_for(ws.recv(), timeout=timeout) + except asyncio.TimeoutError: + return {"_timeout": True, "chunks": chunks, "notifs": notifs} + m = json.loads(raw) + if m.get("method") == "session/update": + update = m.get("params", {}).get("update", {}) + if update.get("sessionUpdate") == "agent_message_chunk": + chunks.append(update.get("content", {}).get("text", "")) + else: + notifs.append(update.get("sessionUpdate")) + continue + if m.get("method"): # other server->client notification + notifs.append(m.get("method")) + continue + if m.get("id") == req_id: + m["chunks"] = chunks + m["notifs"] = notifs + return m + + # 1. initialize + r = await call("initialize", {"protocolVersion": 1, "clientInfo": {"name": "acp-ws-smoke", "version": "0"}}) + res = r.get("result", {}) + check( + res.get("protocolVersion") == 1 and "agentCapabilities" in res, + "initialize", + f"protocolVersion={res.get('protocolVersion')} caps={list(res.get('agentCapabilities', {}).keys())}", + ) + + # 2. session/new + r = await call("session/new", {"cwd": "/home/agent", "mcpServers": []}) + sid = r.get("result", {}).get("sessionId", "") + check(sid.startswith("sess_"), "session/new", f"sessionId={sid[:20]}…") + + # 3./4. session/prompt — stream + stopReason (hits the live model) + r = await call( + "session/prompt", + {"sessionId": sid, "prompt": [{"type": "text", "text": "Reply with exactly one word: PONG"}]}, + timeout=90, + ) + stream = "".join(r.get("chunks", [])) + stop_reason = r.get("result", {}).get("stopReason") + check(len(stream) > 0, "prompt → agent_message_chunk stream", f"{len(stream)} chars: {stream[:40]!r}") + check(stop_reason == "end_turn", "prompt → stopReason", f"stopReason={stop_reason}") + + # 5. session/resume + r = await call("session/resume", {"sessionId": sid, "cwd": "/home/agent", "mcpServers": []}) + check("result" in r and not r.get("error"), "session/resume", f"result={r.get('result')}") + + # 6. /model — config command reply renders back over ACP + r = await call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "/model"}]}, timeout=30) + body = "".join(r.get("chunks", [])) or json.dumps(r.get("result") or r.get("error") or {}) + check( + bool(r.get("chunks")) or "model" in body.lower() or bool(r.get("error")), + "/model reply renders back to ACP", + f"chunks={len(r.get('chunks', []))} body={body[:60]!r}", + ) + + # 7. /reset — session command reply renders back over ACP + r = await call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "/reset"}]}, timeout=30) + body = "".join(r.get("chunks", [])) or json.dumps(r.get("result") or r.get("error") or {}) + check( + bool(r.get("chunks")) or "reset" in body.lower() or bool(r.get("error")), + "/reset reply renders back to ACP", + f"chunks={len(r.get('chunks', []))} body={body[:60]!r}", + ) + + passed = sum(1 for ok, _ in results if ok) + total = len(results) + print(f"\nRESULT: {passed}/{total} passed", flush=True) + return 0 if passed == total else 2 + + +if __name__ == "__main__": + sys.exit(asyncio.run(main())) From 26433493d331d187c9e371e14059099ab395ba24 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 17:18:49 +0800 Subject: [PATCH 17/49] test(acp): edge-case coverage (emoji/Unicode) + streaming slicer unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fills the Unicode/emoji test gap. Extracts the incremental delta logic into a pure `stream_delta(sent_len, full_text)` so the char-boundary safety is unit-testable (behavior unchanged), then adds: - acp_streaming (6): append reconstructs exactly; multi-byte codepoints (astral emoji / ZWJ family / flag / VS16 / CJK) never split across snapshots; emoji emitted whole in one delta; mid-codepoint sent_len skipped not panicked; no-new-text / empty → None. - acp_conformance edge (5 more): ContentBlock + SessionNotification round-trip for astral emoji, ZWJ family, regional-indicator flag, VS16, astral CJK, mixed run; boundary strings (empty / whitespace / JSON-special / control chars / 4KB); all five StopReason variants; multi-block emoji prompt. 17 ACP tests total, all green (clippy -D warnings clean, workspace tests pass). Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 164 +++++++++++++++++- 1 file changed, 156 insertions(+), 8 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 244e820c4..bc60e8422 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -54,6 +54,21 @@ impl AcpConfig { } } +/// Incremental text to stream, given the bytes already sent (`sent_len`) and the +/// latest full-text snapshot. Slices via `str::get` (never byte-index `[..]`), so a +/// `sent_len` that lands mid-codepoint — possible with CJK / 顏文字 / emoji only on a +/// non-append snapshot rewrite — yields `None` (caller skips the frame; the next +/// snapshot re-covers) instead of panicking. In the normal append case `sent_len` is +/// always the byte length of a prior valid snapshot and therefore a char boundary of +/// the new text, so a multi-byte codepoint is always emitted whole, never split. +/// Returns `None` when there is nothing new to send. +fn stream_delta(sent_len: usize, full_text: &str) -> Option<&str> { + match full_text.get(sent_len..) { + Some(d) if !d.is_empty() => Some(d), + _ => None, + } +} + /// Whether ACP frame tracing is on (`OPENAB_ACP_TRACE=1|true`). When set, every /// JSON-RPC frame on the upstream client↔gateway hop is logged in both directions /// (`dir="in"` / `dir="out"`). Off by default; enable to capture real traffic — e.g. @@ -627,14 +642,11 @@ async fn handle_session_prompt( recv = tokio::time::timeout(timeout, reply_rx.recv()) => { match recv { Ok(Some(ReplyChunk::Text(full_text))) => { - // Emit new text as an `agent_message_chunk` update. - // Slice via `get` (not byte-index `[..]`) so a `sent_len` - // that lands mid-codepoint — possible with CJK / 顏文字 / - // emoji if a snapshot is ever non-append — skips this frame - // instead of panicking; the next snapshot re-covers it. - let delta = match full_text.get(sent_len..) { - Some(d) if !d.is_empty() => d, - _ => continue, + // Emit new text as an `agent_message_chunk` update. See + // `stream_delta` for the char-boundary safety guarantee. + let delta = match stream_delta(sent_len, &full_text) { + Some(d) => d, + None => continue, }; sent_len = full_text.len(); @@ -847,4 +859,140 @@ mod acp_conformance { "prompt": [{ "type": "text", "text": "PING" }] })); } + + // --- edge cases: emoji / Unicode / boundary strings (round-trip) --- + + // The multi-byte / multi-codepoint cases a naive wire handler mangles: + // astral-plane emoji, ZWJ sequence, regional-indicator flag, VS16 emoji, + // astral-plane CJK, and a mixed run. + const EDGE_TEXT: &[&str] = &[ + "🎉", // U+1F389, 4-byte astral emoji + "👨‍👩‍👧‍👦", // ZWJ family (7 codepoints joined by ZWJ) + "🇹🇼", // regional-indicator pair (flag) + "❤️", // U+2764 + U+FE0F (VS16) + "𠀀", // U+20000, astral-plane CJK + "🎉 你好 (๑•̀ㅂ•́)و ❤️", // mixed emoji + CJK + kaomoji + VS16 + ]; + + #[test] + fn content_block_emoji_and_unicode() { + for e in EDGE_TEXT { + conforms::(json!({ "type": "text", "text": e })); + } + } + + #[test] + fn session_update_emoji_chunk() { + for e in EDGE_TEXT { + conforms::(json!({ + "sessionId": "sess_00000000-0000-0000-0000-000000000000", + "update": { + "sessionUpdate": "agent_message_chunk", + "content": { "type": "text", "text": e } + } + })); + } + } + + #[test] + fn content_block_boundary_strings() { + // empty, whitespace/newlines/tabs, JSON-special chars, control chars, and a + // long string — all must round-trip as plain text. + let long = "x".repeat(4096); + for s in [ + "", + " \n\t ", + "quote:\" backslash:\\ slash:/ braces:{}[]", + "ctrl:\u{0001}\u{001f} unit-sep", + long.as_str(), + ] { + conforms::(json!({ "type": "text", "text": s })); + } + } + + #[test] + fn prompt_response_all_stop_reasons() { + for sr in ["end_turn", "max_tokens", "max_turn_requests", "refusal", "cancelled"] { + conforms::(json!({ "stopReason": sr })); + } + } + + #[test] + fn prompt_request_multi_block_emoji() { + conforms::(json!({ + "sessionId": "sess_00000000-0000-0000-0000-000000000000", + "prompt": [ + { "type": "text", "text": "line 1 🎉" }, + { "type": "text", "text": "你好 ❤️" } + ] + })); + } +} + +// --------------------------------------------------------------------------- +// Streaming slicer — the char-boundary-safe incremental delta logic. A multi-byte +// codepoint (emoji, CJK) would be split here if the wire used byte indexing; these +// pin that it never happens. +// --------------------------------------------------------------------------- +#[cfg(test)] +mod acp_streaming { + use super::stream_delta; + + /// Replay a sequence of full-text snapshots through the exact loop logic + /// (`stream_delta` + advancing `sent_len`) and return the concatenated deltas. + fn replay(snapshots: &[&str]) -> String { + let mut sent = 0usize; + let mut out = String::new(); + for snap in snapshots { + if let Some(delta) = stream_delta(sent, snap) { + out.push_str(delta); + sent = snap.len(); + } + } + out + } + + #[test] + fn append_reconstructs_exactly() { + assert_eq!(replay(&["", "H", "Hi", "Hi ", "Hi there"]), "Hi there"); + } + + #[test] + fn multibyte_codepoints_never_split() { + // each snapshot appends a whole multi-byte grapheme; reconstruction is exact + let snaps = [ + "a", + "a🎉", + "a🎉你", + "a🎉你👨‍👩‍👧‍👦", + "a🎉你👨‍👩‍👧‍👦🇹🇼", + "a🎉你👨‍👩‍👧‍👦🇹🇼❤️", + ]; + assert_eq!(replay(&snaps), *snaps.last().unwrap()); + } + + #[test] + fn emoji_appears_whole_in_one_delta() { + // "ab" already sent; next snapshot adds a 4-byte emoji → delta is the whole emoji + assert_eq!(stream_delta(2, "ab🎉"), Some("🎉")); + } + + #[test] + fn mid_codepoint_sent_len_is_skipped_not_panicked() { + // sent_len inside the 4-byte emoji (a non-append rewrite) → None, never a panic + assert_eq!(stream_delta(1, "🎉"), None); + assert_eq!(stream_delta(2, "🎉"), None); + assert_eq!(stream_delta(3, "🎉"), None); + } + + #[test] + fn no_new_text_returns_none() { + assert_eq!(stream_delta(5, "hello"), None); // sent == len + assert_eq!(stream_delta(9, "hello"), None); // sent beyond len (shrink/rewrite) + } + + #[test] + fn empty_snapshot_returns_none() { + assert_eq!(stream_delta(0, ""), None); + } } From 76c6554a29c7a6bb1c6e99eb9956ae2b40cd5f20 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 17:45:35 +0800 Subject: [PATCH 18/49] fix(format): grapheme-safe, whitespace-preferred message splitting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit split_message's hard-split iterated by char (Unicode scalar), so it could break a grapheme cluster mid-way — splitting an emoji ZWJ sequence, a VS16 emoji, a regional-indicator flag, or a combining mark across two messages. It also broke words mid-token. Now the hard-split walks grapheme clusters (unicode-segmentation) so a codepoint sequence is never split; outside code fences it also backtracks to the last whitespace so words / CJK / emoji stay intact (code fences stay grapheme-safe but are not reflowed at spaces). New `split_point` / `first_grapheme_len` helpers. Tests: grapheme clusters never split (astral emoji / ZWJ family / flag / VS16 / astral CJK) across several limits; plain split prefers whitespace; long CJK run breaks between characters with all content preserved; fenced emoji hard-split stays grapheme-safe. All existing split_message tests still pass. Co-Authored-By: Claude Opus 4.8 --- Cargo.lock | 7 ++ crates/openab-core/Cargo.toml | 1 + crates/openab-core/src/format.rs | 152 ++++++++++++++++++++++++++----- 3 files changed, 137 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78afc7156..85341ca9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2253,6 +2253,7 @@ dependencies = [ "toml_edit", "tracing", "tracing-subscriber", + "unicode-segmentation", "unicode-width", "urlencoding", "uuid", @@ -3826,6 +3827,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + [[package]] name = "unicode-width" version = "0.2.2" diff --git a/crates/openab-core/Cargo.toml b/crates/openab-core/Cargo.toml index d375a7f4b..9d8b7389d 100644 --- a/crates/openab-core/Cargo.toml +++ b/crates/openab-core/Cargo.toml @@ -26,6 +26,7 @@ bytes = "1" base64 = "0.22" image = { version = "0.25", default-features = false, features = ["jpeg", "png", "gif", "webp"] } unicode-width = "0.2" +unicode-segmentation = "1" pulldown-cmark = { version = "0.13", default-features = false } tokio-tungstenite = { version = "0.21", features = ["rustls-tls-webpki-roots"] } rustls = { version = "0.22", optional = true } diff --git a/crates/openab-core/src/format.rs b/crates/openab-core/src/format.rs index 3c5f3ea4f..edc32b2ab 100644 --- a/crates/openab-core/src/format.rs +++ b/crates/openab-core/src/format.rs @@ -1,3 +1,38 @@ +use unicode_segmentation::UnicodeSegmentation; + +/// Byte length of the first grapheme cluster of `s` (0 if empty). Used to guarantee +/// forward progress when a single grapheme is wider than the target width. +fn first_grapheme_len(s: &str) -> usize { + s.graphemes(true).next().map_or(0, str::len) +} + +/// Byte index at which to cut `s` so the prefix is at most `max_chars` Unicode scalar +/// values **without splitting a grapheme cluster** (emoji, ZWJ sequences, regional- +/// indicator flags, VS16, combining marks all stay whole). When `word_wrap` and the cut +/// would land mid-word, it backtracks to just after the last whitespace in the prefix so +/// words / CJK runs are not broken mid-token. Returns `0` when not even the first +/// grapheme fits in `max_chars` (the caller decides whether to flush or force it). +fn split_point(s: &str, max_chars: usize, word_wrap: bool) -> usize { + let mut chars = 0usize; + let mut byte = 0usize; + let mut last_ws_byte = 0usize; // byte index just past the last whitespace grapheme + for (start, g) in s.grapheme_indices(true) { + let g_chars = g.chars().count(); + if chars + g_chars > max_chars { + break; + } + chars += g_chars; + byte = start + g.len(); + if g.chars().all(char::is_whitespace) { + last_ws_byte = byte; + } + } + if word_wrap && byte < s.len() && last_ws_byte > 0 { + return last_ws_byte; + } + byte +} + /// Split text into chunks at line boundaries, each <= limit Unicode characters (UTF-8 safe). /// Discord's message limit counts Unicode characters, not bytes. /// @@ -5,7 +40,12 @@ /// code block, the current chunk is closed with ``` and the next chunk is reopened with /// the original opener (preserving language tag), so each chunk renders correctly. /// -/// Invariant: every returned chunk satisfies `chunk.chars().count() <= limit`. +/// Hard-splitting an over-long line breaks on **grapheme cluster** boundaries (never +/// mid-emoji / ZWJ sequence / combining mark / CJK codepoint); outside code fences it +/// also prefers whitespace boundaries so words stay intact. +/// +/// Invariant: every returned chunk satisfies `chunk.chars().count() <= limit`, except a +/// single grapheme cluster wider than `limit` (pathological), which is emitted whole. pub fn split_message(text: &str, limit: usize) -> Vec { if text.chars().count() <= limit { return vec![text.to_string()]; @@ -103,9 +143,11 @@ pub fn split_message(text: &str, limit: usize) -> Vec { // If limit can't even fit overhead, fall back to unfenced hard-split. let capacity = limit.saturating_sub(overhead); if let Some(opener) = fence_opener.as_ref().filter(|_| capacity > 0) { - // Fenced hard-split: each mid chunk = opener\n + chars + \n``` + // Fenced hard-split: each mid chunk = opener\n + chars + \n```. + // Grapheme-safe (never split an emoji / ZWJ / combining mark); no + // word-wrap — code must not be reflowed at spaces. let opener_len = opener.chars().count(); - let mut chars = line.chars().peekable(); + let mut rest = line; // Fill remaining space in current chunk first. let avail_first = if current_len > 0 { @@ -113,16 +155,12 @@ pub fn split_message(text: &str, limit: usize) -> Vec { } else { capacity }; - for _ in 0..avail_first { - if let Some(ch) = chars.next() { - current.push(ch); - current_len += 1; - } else { - break; - } - } + let cut = split_point(rest, avail_first, false); + current.push_str(&rest[..cut]); + current_len += rest[..cut].chars().count(); + rest = &rest[cut..]; - while chars.peek().is_some() { + while !rest.is_empty() { // Close current fenced chunk. current.push_str("\n```"); chunks.push(std::mem::take(&mut current)); @@ -130,24 +168,39 @@ pub fn split_message(text: &str, limit: usize) -> Vec { current.push_str(opener); current.push('\n'); current_len = opener_len + 1; - for _ in 0..capacity { - if let Some(ch) = chars.next() { - current.push(ch); - current_len += 1; - } else { - break; - } + let mut cut = split_point(rest, capacity, false); + if cut == 0 { + cut = first_grapheme_len(rest); // grapheme wider than capacity } + current.push_str(&rest[..cut]); + current_len += rest[..cut].chars().count(); + rest = &rest[cut..]; } } else { // Plain hard-split (no fence or limit too small for fence wrapping). - for ch in line.chars() { - if current_len >= limit { + // Grapheme-safe + prefer whitespace boundaries so words / CJK / emoji + // stay intact. + let mut rest = line; + while !rest.is_empty() { + let avail = limit.saturating_sub(current_len); + let mut cut = split_point(rest, avail, true); + if cut == 0 { + if current.is_empty() { + cut = first_grapheme_len(rest); // grapheme wider than limit + } else { + // Nothing more fits in this chunk — flush and retry fresh. + chunks.push(std::mem::take(&mut current)); + current_len = 0; + continue; + } + } + current.push_str(&rest[..cut]); + current_len += rest[..cut].chars().count(); + rest = &rest[cut..]; + if !rest.is_empty() { chunks.push(std::mem::take(&mut current)); current_len = 0; } - current.push(ch); - current_len += 1; } } } else { @@ -324,4 +377,57 @@ mod tests { ); } } + + #[test] + fn grapheme_clusters_never_split() { + use unicode_segmentation::UnicodeSegmentation; + // multi-codepoint graphemes a char-based split would break: astral emoji, + // ZWJ family, flag, VS16, astral CJK, plus plain BMP chars. + let graphemes = ["🎉", "👨‍👩‍👧‍👦", "🇹🇼", "❤️", "𠀀", "a", "你", "🙂"]; + let line: String = graphemes.iter().copied().cycle().take(48).collect(); + for limit in [5, 8, 13, 20] { + let chunks = split_message(&line, limit); + // No grapheme split: flattening chunk graphemes reproduces the original + // grapheme sequence exactly (a split grapheme would re-segment differently). + let flat: Vec<&str> = chunks.iter().flat_map(|c| c.graphemes(true)).collect(); + let orig: Vec<&str> = line.graphemes(true).collect(); + assert_eq!(flat, orig, "grapheme cluster split at limit {limit}"); + } + } + + #[test] + fn plain_hard_split_prefers_whitespace() { + // A long run of short words: chunks should break at spaces, not mid-word. + let line = "alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo"; + let chunks = split_message(line, 20); + assert_length_invariant(&chunks, 20); + assert!(chunks.len() > 1); + let rejoined = chunks.iter().map(|c| c.trim()).collect::>().join(" "); + assert_eq!( + rejoined.split_whitespace().collect::>(), + line.split_whitespace().collect::>(), + "words were broken or lost by the hard-split" + ); + } + + #[test] + fn cjk_hard_split_breaks_between_characters() { + // A long CJK run (no whitespace) must break on codepoint/grapheme bounds and + // preserve every character. + let line: String = std::iter::repeat_n('好', 50).collect(); + let chunks = split_message(&line, 10); + assert_length_invariant(&chunks, 10); + assert_eq!(chunks.concat(), line); + } + + #[test] + fn fenced_hard_split_grapheme_safe() { + // Emoji inside a code fence: grapheme-safe, all content preserved. + let content: String = std::iter::repeat("🎉❤️你").take(20).collect(); + let text = format!("```\n{content}\n```"); + let chunks = split_message(&text, 20); + assert_length_invariant(&chunks, 20); + let party: usize = chunks.iter().map(|c| c.matches('🎉').count()).sum(); + assert_eq!(party, 20, "emoji lost across fenced hard-split"); + } } From bc46be1b74e875327fa2808fd1040cb7d283370a Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 22:31:20 +0800 Subject: [PATCH 19/49] fix(acp-smoke): treat JSON-RPC errors/timeouts as failures (F13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /model and /reset checks passed on `bool(r.get("error"))`, so a JSON-RPC error counted as a successful command render. Now a check passes only on a real rendered reply — no error, no timeout, chunks present, and the expected keyword in the streamed text. Verified 7/7 still green against a live deployment. Addresses review finding F13. Co-Authored-By: Claude Opus 4.8 --- scripts/acp-ws-smoke.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py index 0704f32c4..a224ec77b 100755 --- a/scripts/acp-ws-smoke.py +++ b/scripts/acp-ws-smoke.py @@ -128,22 +128,24 @@ async def call(method, params=None, timeout=8): r = await call("session/resume", {"sessionId": sid, "cwd": "/home/agent", "mcpServers": []}) check("result" in r and not r.get("error"), "session/resume", f"result={r.get('result')}") - # 6. /model — config command reply renders back over ACP + # 6. /model — config command reply renders back over ACP. + # A JSON-RPC error or a timeout is a FAILURE, not a pass: a check passes only + # on a real rendered reply (chunks present with the expected text). r = await call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "/model"}]}, timeout=30) - body = "".join(r.get("chunks", [])) or json.dumps(r.get("result") or r.get("error") or {}) + text = "".join(r.get("chunks", [])) check( - bool(r.get("chunks")) or "model" in body.lower() or bool(r.get("error")), + not r.get("error") and not r.get("_timeout") and bool(r.get("chunks")) and "model" in text.lower(), "/model reply renders back to ACP", - f"chunks={len(r.get('chunks', []))} body={body[:60]!r}", + f"chunks={len(r.get('chunks', []))} err={r.get('error')} timeout={r.get('_timeout', False)} body={text[:60]!r}", ) - # 7. /reset — session command reply renders back over ACP + # 7. /reset — session command reply renders back over ACP. r = await call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "/reset"}]}, timeout=30) - body = "".join(r.get("chunks", [])) or json.dumps(r.get("result") or r.get("error") or {}) + text = "".join(r.get("chunks", [])) check( - bool(r.get("chunks")) or "reset" in body.lower() or bool(r.get("error")), + not r.get("error") and not r.get("_timeout") and bool(r.get("chunks")) and "reset" in text.lower(), "/reset reply renders back to ACP", - f"chunks={len(r.get('chunks', []))} body={body[:60]!r}", + f"chunks={len(r.get('chunks', []))} err={r.get('error')} timeout={r.get('_timeout', False)} body={text[:60]!r}", ) passed = sum(1 for ok, _ in results if ok) From 33fded8b8c169650f1e9be084b097065f7af1496 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 22:46:17 +0800 Subject: [PATCH 20/49] docs(acp): correct overclaimed cancel/verification status (F15) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit session/cancel is downgraded from "✅ conformant" to ⚠️ partial: the notification is accepted and the waiter ends with stopReason:"cancelled", but cancellation is not propagated to the backend (F3). The live-verification section drops the unqualified "session/cancel drives a real backend" claim and adds a Known-limits block recording the two verified-but-unfixed defects — long replies truncate over ACP (F2) and cancel does not stop the backend (F3) — as tracked follow-ups. Addresses review finding F15. Co-Authored-By: Claude Opus 4.8 --- docs/acp-official-methods.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/acp-official-methods.md b/docs/acp-official-methods.md index d593b33eb..5d204195c 100644 --- a/docs/acp-official-methods.md +++ b/docs/acp-official-methods.md @@ -46,7 +46,7 @@ Directions use the ACP roles: the **Agent** answers prompts (here, OpenAB); the | Method | Direction | Purpose | OpenAB base | |---|---|---|---| -| `session/cancel` | Client → Agent | Cancel in-flight work (one-way, no response) | ✅ conformant (notification; prompt ends `stopReason:"cancelled"`) | +| `session/cancel` | Client → Agent | Cancel in-flight work (one-way, no response) | ⚠️ partial — the one-way notification is accepted and the gateway waiter ends with `stopReason:"cancelled"`, but cancellation is **not propagated to the backend** agent/model, which keeps running. Backend-propagating cancel is a tracked follow-up (review F3). | | `session/update` | Agent → Client | Stream session events | ✅ `agent_message_chunk` (text). Other variants (`agent_thought_chunk`, `tool_call`, `tool_call_update`, `plan`, `available_commands_update`, `usage_update`, …) are Phase 2 / not forwarded | | `$/cancel_request` | Bidirectional | Cancel an in-flight JSON-RPC request | ⛔ | @@ -82,11 +82,19 @@ The chat subset is **wire-conformant** with ACP Schema v1.19.0: ### Live verification status -- **Verified end-to-end (2026-07-17)** — the chat subset (`initialize` → `session/new` - / `session/resume` → `session/prompt` → streamed `session/update` `agent_message_chunk` - → `{stopReason}`, plus `session/cancel`) drives a real backend (cursor-agent) and - streams replies to a WebSocket client (a Chrome side-panel extension + a raw - `ws` client). +- **Verified end-to-end (2026-07-17; re-checked 2026-07-18)** — the chat subset + (`initialize` → `session/new` / `session/resume` → `session/prompt` → streamed + `session/update` `agent_message_chunk` → `{stopReason}`) drives a real backend + (cursor-agent) and streams replies to a WebSocket client (a Chrome side-panel + extension + a raw `ws` client). `scripts/acp-ws-smoke.py` reproduces this. +- **Known limits (verified 2026-07-18; tracked follow-ups, not yet fixed)** — + - **Long replies truncate.** A reply larger than the adapter's message limit is + split into several messages, but the ACP reply route is closed after the first + one, so overflow chunks are dropped (a 900-line reply arrived as ~413 lines). + Review F2. + - **Cancel does not stop the backend.** `session/cancel` returns + `stopReason:"cancelled"` to the waiter, but the downstream model/tool work + continues. Review F3. - **Still unverified** — field-level exactness of `agentCapabilities` / `clientCapabilities` sub-objects against a *third-party* ACP client (e.g. Zed), and `ContentBlock` variants beyond `text` (image / audio / resource). From dd3dc4e653ee4d0342a1d96c069379e3c9d7e8fa Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 23:04:18 +0800 Subject: [PATCH 21/49] fix(acp): include acp in embedded-server feature guards (F7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three `#[cfg(any(...))]` guards (the `mod unified_adapter` gate, the pool/ unified-platform setup, and the embedded HTTP-server block that mounts `/acp`) listed the webhook platforms but omitted `acp`, so `--no-default-features --features acp` compiled the embedded server out before the `acp_enabled` runtime check could run — contradicting the documented ACP-only `openab run` deployment. Added `feature = "acp"` to all three. Verified `cargo build --no-default-features --features acp` now succeeds. Addresses review finding F7. Co-Authored-By: Claude Opus 4.8 --- src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.rs b/src/main.rs index b4947c024..9ca59e020 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod ctl; feature = "googlechat", feature = "wecom", feature = "teams", + feature = "acp", ))] mod unified_adapter; use openab_core::acp; @@ -360,6 +361,7 @@ async fn main() -> anyhow::Result<()> { feature = "googlechat", feature = "wecom", feature = "teams", + feature = "acp", ))] let unified_platform_enabled = has_unified_platform(&cfg); @@ -906,6 +908,7 @@ async fn main() -> anyhow::Result<()> { feature = "googlechat", feature = "wecom", feature = "teams", + feature = "acp", ))] let (_unified_handle, shared_unified_adapter) = { use openab_core::gateway::{process_gateway_event, GatewayEventContext}; From 988193e568c9aa3d9684691c5457896de47367fc Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 23:22:51 +0800 Subject: [PATCH 22/49] fix(format): bound over-limit graphemes so every chunk stays <= limit (F4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The grapheme fallback emitted a whole grapheme cluster even when it was wider than the caller's limit, producing a chunk above a hard platform limit (undeliverable on Discord/Slack, and it could eat a mention footer's reserved capacity). Replace first_grapheme_len with codepoint_split_point: when — and only when — a single grapheme is wider than the target width, split it by codepoint as a last resort so the chunk still satisfies the limit (a cluster wider than the whole limit cannot be kept intact and also fit). Tests: oversized grapheme respects limit + preserves content across limits 2/3/5; mention-reserve path honors the reduced limit. Adjusted grapheme_clusters_never_split to limits >= the widest grapheme (oversized-split is the new dedicated test). Addresses review finding F4. Co-Authored-By: Claude Opus 4.8 --- crates/openab-core/src/format.rs | 56 +++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/crates/openab-core/src/format.rs b/crates/openab-core/src/format.rs index edc32b2ab..4fa1ce9e1 100644 --- a/crates/openab-core/src/format.rs +++ b/crates/openab-core/src/format.rs @@ -1,9 +1,14 @@ use unicode_segmentation::UnicodeSegmentation; -/// Byte length of the first grapheme cluster of `s` (0 if empty). Used to guarantee -/// forward progress when a single grapheme is wider than the target width. -fn first_grapheme_len(s: &str) -> usize { - s.graphemes(true).next().map_or(0, str::len) +/// Byte index after at most `max_chars` (>=1) Unicode scalar values — a last-resort +/// split used ONLY when a single grapheme cluster is itself wider than the target width. +/// It splits inside the cluster by codepoint (unavoidable: a cluster wider than the +/// whole limit cannot be both kept intact and fit) so every emitted chunk still honors +/// the caller's hard char limit. Guarantees forward progress (>=1 char). +fn codepoint_split_point(s: &str, max_chars: usize) -> usize { + s.char_indices() + .nth(max_chars.max(1)) + .map_or(s.len(), |(i, _)| i) } /// Byte index at which to cut `s` so the prefix is at most `max_chars` Unicode scalar @@ -44,8 +49,9 @@ fn split_point(s: &str, max_chars: usize, word_wrap: bool) -> usize { /// mid-emoji / ZWJ sequence / combining mark / CJK codepoint); outside code fences it /// also prefers whitespace boundaries so words stay intact. /// -/// Invariant: every returned chunk satisfies `chunk.chars().count() <= limit`, except a -/// single grapheme cluster wider than `limit` (pathological), which is emitted whole. +/// Invariant: every returned chunk satisfies `chunk.chars().count() <= limit`. A single +/// grapheme cluster wider than `limit` is split by codepoint as a last resort so the +/// limit still holds (such a cluster cannot be kept intact and also fit). pub fn split_message(text: &str, limit: usize) -> Vec { if text.chars().count() <= limit { return vec![text.to_string()]; @@ -170,7 +176,8 @@ pub fn split_message(text: &str, limit: usize) -> Vec { current_len = opener_len + 1; let mut cut = split_point(rest, capacity, false); if cut == 0 { - cut = first_grapheme_len(rest); // grapheme wider than capacity + // grapheme wider than capacity → codepoint-split to stay <= limit + cut = codepoint_split_point(rest, capacity); } current.push_str(&rest[..cut]); current_len += rest[..cut].chars().count(); @@ -186,7 +193,8 @@ pub fn split_message(text: &str, limit: usize) -> Vec { let mut cut = split_point(rest, avail, true); if cut == 0 { if current.is_empty() { - cut = first_grapheme_len(rest); // grapheme wider than limit + // grapheme wider than limit → codepoint-split to stay <= limit + cut = codepoint_split_point(rest, avail); } else { // Nothing more fits in this chunk — flush and retry fresh. chunks.push(std::mem::take(&mut current)); @@ -385,7 +393,10 @@ mod tests { // ZWJ family, flag, VS16, astral CJK, plus plain BMP chars. let graphemes = ["🎉", "👨‍👩‍👧‍👦", "🇹🇼", "❤️", "𠀀", "a", "你", "🙂"]; let line: String = graphemes.iter().copied().cycle().take(48).collect(); - for limit in [5, 8, 13, 20] { + // Limits >= the widest grapheme (the 7-scalar ZWJ family) so every grapheme fits + // and none is split. Graphemes WIDER than the limit are the last-resort codepoint + // split, covered by `oversized_grapheme_still_respects_limit`. + for limit in [8, 13, 20] { let chunks = split_message(&line, limit); // No grapheme split: flattening chunk graphemes reproduces the original // grapheme sequence exactly (a split grapheme would re-segment differently). @@ -430,4 +441,31 @@ mod tests { let party: usize = chunks.iter().map(|c| c.matches('🎉').count()).sum(); assert_eq!(party, 20, "emoji lost across fenced hard-split"); } + + #[test] + fn oversized_grapheme_still_respects_limit() { + // A single grapheme wider than the limit must still be bounded to <= limit + // (last-resort codepoint split) so every chunk stays deliverable; content is + // preserved byte-exact. + let family = "👨‍👩‍👧‍👦"; // one grapheme, 7 scalar values + for limit in [2, 3, 5] { + let chunks = split_message(family, limit); + assert_length_invariant(&chunks, limit); + assert_eq!(chunks.concat(), family, "content lost at limit {limit}"); + } + } + + #[test] + fn oversized_grapheme_with_mention_reserve() { + // Discord path: the caller reduces the limit by a mention-footer reserve before + // calling split_message; the reduced limit must still hold even when a single + // grapheme is wider than it, so the footer's reserved capacity is never eaten. + let text = format!("❤️{fam}{fam}", fam = "👨‍👩‍👧‍👦"); + let limit = 10; + let reserve = 4; + let effective = limit - reserve; // 6 + let chunks = split_message(&text, effective); + assert_length_invariant(&chunks, effective); + assert_eq!(chunks.concat(), text, "content lost with mention reserve"); + } } From 67281957f2df0a8fb41d394127da3e2bac5b560f Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 23:33:17 +0800 Subject: [PATCH 23/49] fix(acp): trace frames at debug! + truncate, document content logging (F12) OPENAB_ACP_TRACE logged full prompts/responses/capabilities at info!, so enabling it surfaced message content at the default log level and dumped whole frames. Frames now log at debug! (never at the default level) and are truncated to 512 scalar values via trace_frame, and acp_trace_enabled's doc states plainly that it is an opt-in debugging tool that records message content, for trusted environments only. Addresses review finding F12. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index bc60e8422..6944c6c20 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -70,15 +70,32 @@ fn stream_delta(sent_len: usize, full_text: &str) -> Option<&str> { } /// Whether ACP frame tracing is on (`OPENAB_ACP_TRACE=1|true`). When set, every -/// JSON-RPC frame on the upstream client↔gateway hop is logged in both directions -/// (`dir="in"` / `dir="out"`). Off by default; enable to capture real traffic — e.g. -/// to validate the generated-type round-trip against what clients/agents actually emit. +/// JSON-RPC frame on the upstream client↔gateway hop is logged (at `debug!`) in both +/// directions (`dir="in"` / `dir="out"`). +/// +/// **This is an opt-in debugging tool that records message CONTENT** — prompts, replies, +/// and negotiated capabilities appear in the logs (truncated, see `trace_frame`). It is +/// off by default and emits at `debug!` so it never surfaces at the default log level; +/// only enable it in a trusted environment when you need to inspect real ACP traffic +/// (e.g. to validate the generated-type round-trip against what clients/agents emit). pub(crate) fn acp_trace_enabled() -> bool { std::env::var("OPENAB_ACP_TRACE") .map(|v| v == "true" || v == "1") .unwrap_or(false) } +/// Truncate a frame for trace logging so a large prompt/reply doesn't dump a huge line +/// (and doesn't record the *complete* content). Keeps the first `CAP` scalar values. +fn trace_frame(s: &str) -> std::borrow::Cow<'_, str> { + const CAP: usize = 512; + let total = s.chars().count(); + if total <= CAP { + return std::borrow::Cow::Borrowed(s); + } + let end = s.char_indices().nth(CAP).map_or(s.len(), |(i, _)| i); + std::borrow::Cow::Owned(format!("{}…(+{} chars)", &s[..end], total - CAP)) +} + // --------------------------------------------------------------------------- // ACP Session tracking // --------------------------------------------------------------------------- @@ -238,7 +255,7 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let send_task = tokio::spawn(async move { while let Some(msg) = out_rx.recv().await { if trace { - info!(connection = %send_conn, dir = "out", frame = %msg, "ACP frame"); + debug!(connection = %send_conn, dir = "out", frame = %trace_frame(&msg), "ACP frame"); } if ws_tx.send(Message::Text(msg.into())).await.is_err() { break; @@ -253,7 +270,7 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { }; if trace { - info!(connection = %connection_id, dir = "in", frame = %text, "ACP frame"); + debug!(connection = %connection_id, dir = "in", frame = %trace_frame(&text), "ACP frame"); } let req: JsonRpcRequest = match serde_json::from_str(&text) { From a9ea9f032c7055b3fc8a453f53cb0f396d9d1f34 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sat, 18 Jul 2026 23:57:59 +0800 Subject: [PATCH 24/49] fix(acp): honor JSON-RPC notification vs request id semantics (F8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dispatch collapsed an omitted `id` to `Value::Null`, so notifications executed as requests and got `id:null` responses, unknown notifications got error responses, and `session/cancel` never responded even when sent with an id. Notification detection now uses raw key PRESENCE (`raw.get("id").is_none()`) — serde's `Option` maps both omitted and explicit `null` to `None`, so the struct field cannot distinguish them. A notification never receives a response: request-only methods (initialize/session.new/resume/prompt) sent without an id are ignored (they cannot return a result), and an unknown notification is dropped instead of erroring. A request (id present, incl. null) is always answered; `session/cancel` sent as a request is acknowledged with an empty result. Bad-version/invalid-request errors are likewise sent only for requests. Test: raw key presence distinguishes omitted id / explicit null / numeric id. Addresses review finding F8. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 96 +++++++++++++++---- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 6944c6c20..2e4538869 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -273,30 +273,59 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { debug!(connection = %connection_id, dir = "in", frame = %trace_frame(&text), "ACP frame"); } - let req: JsonRpcRequest = match serde_json::from_str(&text) { - Ok(r) => r, + let raw: Value = match serde_json::from_str(&text) { + Ok(v) => v, Err(e) => { - let err_resp = JsonRpcResponse::error( - Value::Null, - -32700, - format!("Parse error: {e}"), - ); + let err_resp = + JsonRpcResponse::error(Value::Null, -32700, format!("Parse error: {e}")); let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); continue; } }; - // Validate JSON-RPC version (spec requires "2.0") + // JSON-RPC: a message WITHOUT an `id` member is a notification and MUST NOT + // receive any response; a message WITH an `id` (including explicit `null`) is a + // request. serde's `Option` collapses omitted and `null` to the same + // `None`, so notification detection uses raw key PRESENCE on the parsed JSON. + let is_notification = raw.get("id").is_none(); + + let req: JsonRpcRequest = match serde_json::from_value(raw) { + Ok(r) => r, + Err(e) => { + if !is_notification { + let err_resp = + JsonRpcResponse::error(Value::Null, -32600, format!("Invalid Request: {e}")); + let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); + } + continue; + } + }; + + // Validate JSON-RPC version (spec requires "2.0"). Only answer a request. if req.jsonrpc != "2.0" { - let err_resp = JsonRpcResponse::error( - req.id.clone().unwrap_or(Value::Null), - -32600, - "Invalid Request: jsonrpc must be \"2.0\"", - ); - let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); + if !is_notification { + let id = req.id.clone().unwrap_or(Value::Null); + let err_resp = + JsonRpcResponse::error(id, -32600, "Invalid Request: jsonrpc must be \"2.0\""); + let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); + } + continue; + } + + // Request-only methods sent as a notification (no id) cannot return their result, + // so per JSON-RPC they get no response — and we do not execute them as + // fire-and-forget. Only `session/cancel` is a real notification (handled below). + if is_notification + && matches!( + req.method.as_str(), + "initialize" | "session/new" | "session/resume" | "session/prompt" + ) + { + debug!(method = %req.method, "ACP request-only method sent without id (notification) — ignored"); continue; } + // Safe: request-only arms below are only reached when `id` is present. let id = req.id.clone().unwrap_or(Value::Null); match req.method.as_str() { @@ -361,14 +390,23 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { n.notify_one(); } } + // `session/cancel` is a notification: no response when sent as one. If a + // client sent it as a request (with an id), acknowledge with an empty result. + if !is_notification { + let resp = JsonRpcResponse::success(id, json!({})); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + } } _ => { - let resp = JsonRpcResponse::error( - id, - -32601, - format!("Method not found: {}", req.method), - ); - let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + // Unknown method: error a request; ignore an unknown notification. + if !is_notification { + let resp = JsonRpcResponse::error( + id, + -32601, + format!("Method not found: {}", req.method), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + } } } @@ -944,6 +982,24 @@ mod acp_conformance { ] })); } + + // --- JSON-RPC id semantics (F8): omitted id (notification) vs explicit null (request) --- + + #[test] + fn jsonrpc_id_presence_distinguishes_notification() { + // serde's `Option` collapses BOTH omitted id and explicit `id:null` to + // `None`, so notification detection must use raw key PRESENCE (as the dispatch + // does), not the deserialized field. + let notif: Value = + serde_json::from_str(r#"{"jsonrpc":"2.0","method":"session/cancel"}"#).unwrap(); + assert!(notif.get("id").is_none(), "no id member → notification"); + let req_null: Value = + serde_json::from_str(r#"{"jsonrpc":"2.0","method":"session/cancel","id":null}"#).unwrap(); + assert!(req_null.get("id").is_some(), "explicit id:null → request (id member present)"); + let req_num: Value = + serde_json::from_str(r#"{"jsonrpc":"2.0","method":"initialize","id":7}"#).unwrap(); + assert_eq!(req_num.get("id"), Some(&json!(7))); + } } // --------------------------------------------------------------------------- From 6c0c20fa632901e5b40ddbd7587428fa1bd547ac Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 00:08:16 +0800 Subject: [PATCH 25/49] fix(acp): validate required session/new & session/resume params (F9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit session/new ignored its params entirely and session/resume only read sessionId, so malformed requests were silently accepted. Both now validate params against the generated request types (NewSessionRequest / ResumeSessionRequest) and reject missing/malformed required fields with -32602 (session/new needs { cwd, mcpServers }; session/resume needs { sessionId, cwd }). Shape-only — the base still does not propagate cwd/mcpServers (ADR §5); the sessionId sess_ format check remains in the handler. New validate_params helper + test. Addresses review finding F9. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 2e4538869..0fc09394f 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -96,6 +96,17 @@ fn trace_frame(s: &str) -> std::borrow::Cow<'_, str> { std::borrow::Cow::Owned(format!("{}…(+{} chars)", &s[..end], total - CAP)) } +/// Validate a request's `params` against a generated ACP request type `T`, returning a +/// JSON-RPC `-32602` message when a required field is missing or malformed. This checks +/// shape only — the base validates `cwd`/`mcpServers` for conformance but does not yet +/// propagate them (see the base ADR §5); missing `params` is itself invalid. +fn validate_params(params: Option<&Value>) -> Result<(), String> { + let value = params.cloned().unwrap_or(Value::Null); + serde_json::from_value::(value) + .map(|_| ()) + .map_err(|e| format!("Invalid params: {e}")) +} + // --------------------------------------------------------------------------- // ACP Session tracking // --------------------------------------------------------------------------- @@ -340,6 +351,14 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); continue; } + // Required params per schema: { cwd, mcpServers }. + if let Err(msg) = + validate_params::(req.params.as_ref()) + { + let resp = JsonRpcResponse::error(id, -32602, msg); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } let resp = handle_session_new(&sessions, id.clone()).await; let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); } @@ -349,6 +368,15 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); continue; } + // Required params per schema: { sessionId, cwd, mcpServers? }. The + // sessionId's `sess_` shape is checked further in the handler. + if let Err(msg) = + validate_params::(req.params.as_ref()) + { + let resp = JsonRpcResponse::error(id, -32602, msg); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } let resp = handle_session_resume(&sessions, id.clone(), req.params.as_ref()).await; let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); } @@ -1000,6 +1028,22 @@ mod acp_conformance { serde_json::from_str(r#"{"jsonrpc":"2.0","method":"initialize","id":7}"#).unwrap(); assert_eq!(req_num.get("id"), Some(&json!(7))); } + + // --- required-param validation (F9): reject malformed session/new & resume --- + + #[test] + fn session_param_validation() { + use super::validate_params; + // session/new requires { cwd, mcpServers } + assert!(validate_params::(Some(&json!({"cwd": "/w", "mcpServers": []}))).is_ok()); + assert!(validate_params::(Some(&json!({"mcpServers": []}))).is_err(), "missing cwd"); + assert!(validate_params::(Some(&json!({"cwd": "/w"}))).is_err(), "missing mcpServers"); + assert!(validate_params::(None).is_err(), "missing params"); + // session/resume requires { sessionId, cwd } + assert!(validate_params::(Some(&json!({"sessionId": "sess_x", "cwd": "/w", "mcpServers": []}))).is_ok()); + assert!(validate_params::(Some(&json!({"cwd": "/w"}))).is_err(), "missing sessionId"); + assert!(validate_params::(Some(&json!({"sessionId": "sess_x"}))).is_err(), "missing cwd"); + } } // --------------------------------------------------------------------------- From 197eaf37c59eaacd7d73abf8b94646c2d92987cc Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 00:19:21 +0800 Subject: [PATCH 26/49] fix(acp): reject unsupported prompt content blocks instead of dropping (F10) extract_prompt_params filter_map'd the prompt array, silently discarding any non-text block (image / audio / resource / resource_link), so a client's content vanished with no signal. It now returns an error on the first unsupported block type (and on a block missing its type/text), which the caller surfaces as -32602. The base is text-only; plain-string prompts and text blocks are unchanged. New test. Addresses review finding F10. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 63 ++++++++++++++++--- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 0fc09394f..c4331197a 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -785,18 +785,30 @@ fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), Str .to_string(); let prompt = params.get("prompt").ok_or("Missing prompt")?; - // Prompt can be an array of content blocks or a simple string + // Prompt can be an array of content blocks or a simple string. The base is + // text-only: an unsupported block type (image / audio / resource / resource_link) + // is rejected explicitly rather than silently dropped, so the client knows its + // content was not delivered. let text = if let Some(arr) = prompt.as_array() { - arr.iter() - .filter_map(|block| { - if block.get("type").and_then(|t| t.as_str()) == Some("text") { - block.get("text").and_then(|t| t.as_str()) - } else { - None + let mut parts = Vec::with_capacity(arr.len()); + for block in arr { + match block.get("type").and_then(|t| t.as_str()) { + Some("text") => { + let t = block + .get("text") + .and_then(|t| t.as_str()) + .ok_or("Text content block missing 'text'")?; + parts.push(t); } - }) - .collect::>() - .join("\n") + Some(other) => { + return Err(format!( + "Unsupported prompt content block type '{other}' — the base accepts only 'text'" + )); + } + None => return Err("Prompt content block missing 'type'".into()), + } + } + parts.join("\n") } else if let Some(s) = prompt.as_str() { s.to_string() } else { @@ -1044,6 +1056,37 @@ mod acp_conformance { assert!(validate_params::(Some(&json!({"cwd": "/w"}))).is_err(), "missing sessionId"); assert!(validate_params::(Some(&json!({"sessionId": "sess_x"}))).is_err(), "missing cwd"); } + + // --- prompt content blocks (F10): unsupported block types rejected, not dropped --- + + #[test] + fn prompt_rejects_non_text_blocks() { + use super::extract_prompt_params; + // text blocks accepted and concatenated + let (_, text) = extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [{"type": "text", "text": "a"}, {"type": "text", "text": "b"}] + }))) + .unwrap(); + assert_eq!(text, "a\nb"); + // a non-text block (resource_link / image) is an explicit error, never dropped + assert!( + extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [{"type": "text", "text": "hi"}, {"type": "resource_link", "uri": "file:///x"}] + }))) + .is_err(), + "resource_link must be rejected, not silently dropped" + ); + assert!(extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [{"type": "image", "data": "..", "mimeType": "image/png"}] + }))) + .is_err()); + // a plain-string prompt still works + let (_, s) = extract_prompt_params(Some(&json!({"sessionId": "sess_x", "prompt": "hello"}))).unwrap(); + assert_eq!(s, "hello"); + } } // --------------------------------------------------------------------------- From ac50309a8368e0b1236d0ebda10a6db3ebf1a01b Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 00:34:49 +0800 Subject: [PATCH 27/49] fix(acp): lightweight per-connection resource caps (F6) A client could create unlimited sessions and prompt tasks and send arbitrarily large frames. Add deterministic overload caps: MAX_FRAME_BYTES (1 MiB) rejects an oversized inbound frame before parsing; MAX_SESSIONS_PER_CONNECTION (128) bounds session/new; MAX_INFLIGHT_PROMPTS (32) bounds concurrent prompt tasks (finished tasks are reaped first). Each returns a JSON-RPC -32000 overload error. Full backpressure (bounded outbound channel), idle eviction, and global connection/worker limits remain a follow-up (documented as roadmap). Addresses review finding F6 (lightweight scope). Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index c4331197a..ab8e91754 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -30,6 +30,15 @@ use uuid::Uuid; /// Tracks the official schema — see `docs/acp-official-methods.md`. const ACP_PROTOCOL_VERSION: u32 = 1; +/// Lightweight per-connection resource caps: turn unbounded client-driven growth into +/// a deterministic overload error. Full backpressure (bounded outbound channel), idle +/// eviction, and global connection/worker limits are a follow-up (review F6, roadmap). +const MAX_SESSIONS_PER_CONNECTION: usize = 128; +const MAX_INFLIGHT_PROMPTS: usize = 32; +const MAX_FRAME_BYTES: usize = 1 << 20; // 1 MiB per inbound JSON-RPC frame +/// JSON-RPC implementation-defined server error for a hit resource cap. +const ACP_OVERLOADED: i32 = -32000; + // --------------------------------------------------------------------------- // ACP Configuration // --------------------------------------------------------------------------- @@ -280,6 +289,17 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { continue; }; + // Bound inbound frame size before parsing (deterministic overload, not OOM). + if text.len() > MAX_FRAME_BYTES { + let resp = JsonRpcResponse::error( + Value::Null, + ACP_OVERLOADED, + format!("Frame too large ({} bytes; max {MAX_FRAME_BYTES})", text.len()), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + if trace { debug!(connection = %connection_id, dir = "in", frame = %trace_frame(&text), "ACP frame"); } @@ -359,6 +379,16 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); continue; } + // Cap sessions per connection (deterministic overload, not unbounded). + if sessions.lock().await.len() >= MAX_SESSIONS_PER_CONNECTION { + let resp = JsonRpcResponse::error( + id, + ACP_OVERLOADED, + format!("Too many sessions on this connection (max {MAX_SESSIONS_PER_CONNECTION})"), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } let resp = handle_session_new(&sessions, id.clone()).await; let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); } @@ -386,6 +416,17 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); continue; } + // Cap concurrent in-flight prompts per connection (drop finished first). + prompt_tasks.retain(|h| !h.is_finished()); + if prompt_tasks.len() >= MAX_INFLIGHT_PROMPTS { + let resp = JsonRpcResponse::error( + id, + ACP_OVERLOADED, + format!("Too many in-flight prompts (max {MAX_INFLIGHT_PROMPTS})"), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } // session/prompt is async — spawn a task to handle streaming let state_clone = state.clone(); let sessions_clone = sessions.clone(); From 8689e36274a8935adf491e3029481262a8688be6 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 00:49:46 +0800 Subject: [PATCH 28/49] test(acp): handler-level tests exercising the real handlers (F14) Add acp_handlers: call handle_initialize / handle_session_new / handle_session_resume directly and assert their actual output + side effects, not just literal round-trips. Covers the conformant initialize capabilities, session/new minting a sess_ and storing it, and session/resume returning {} + storing for a valid id while rejecting a malformed / missing sessionId with -32602. Addresses review finding F14. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index ab8e91754..fe713b262 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -1197,3 +1197,71 @@ mod acp_streaming { assert_eq!(stream_delta(0, ""), None); } } + +// --------------------------------------------------------------------------- +// Handler-level tests — call the real handlers (not just literal round-trips) and +// assert their actual output + side effects. +// --------------------------------------------------------------------------- +#[cfg(test)] +mod acp_handlers { + use super::{ + handle_initialize, handle_session_new, handle_session_resume, AcpSession, JsonRpcRequest, + }; + use serde_json::json; + use std::collections::HashMap; + use std::sync::Arc; + use uuid::Uuid; + + fn new_sessions() -> Arc>> { + Arc::new(tokio::sync::Mutex::new(HashMap::new())) + } + + #[test] + fn initialize_returns_conformant_capabilities() { + let req = JsonRpcRequest { + jsonrpc: "2.0".into(), + method: "initialize".into(), + id: Some(json!(1)), + params: None, + }; + let v = serde_json::to_value(handle_initialize(&req)).unwrap(); + assert_eq!(v["id"], json!(1)); + let result = &v["result"]; + assert_eq!(result["protocolVersion"], json!(1)); + assert_eq!(result["agentCapabilities"]["loadSession"], json!(false)); + assert!(result["agentCapabilities"]["sessionCapabilities"]["resume"].is_object()); + assert!(result["authMethods"].is_array()); + } + + #[tokio::test] + async fn session_new_mints_and_stores_a_session() { + let sessions = new_sessions(); + let v = serde_json::to_value(handle_session_new(&sessions, json!(2)).await).unwrap(); + let sid = v["result"]["sessionId"].as_str().unwrap(); + assert!(sid.starts_with("sess_"), "sessionId must be sess_: {sid}"); + assert!(sessions.lock().await.contains_key(sid), "session must be stored"); + } + + #[tokio::test] + async fn session_resume_valid_stores_and_invalid_errors() { + let sessions = new_sessions(); + // valid sess_ → {} and the session is (re)stored + let sid = format!("sess_{}", Uuid::new_v4()); + let params = json!({"sessionId": sid, "cwd": "/w", "mcpServers": []}); + let v = serde_json::to_value(handle_session_resume(&sessions, json!(3), Some(¶ms)).await) + .unwrap(); + assert_eq!(v["result"], json!({})); + assert!(sessions.lock().await.contains_key(&sid)); + // malformed sessionId shape → -32602 + let bad = json!({"sessionId": "not-a-session", "cwd": "/w", "mcpServers": []}); + let v = serde_json::to_value(handle_session_resume(&sessions, json!(4), Some(&bad)).await) + .unwrap(); + assert_eq!(v["error"]["code"], json!(-32602)); + // missing sessionId → -32602 + let v = serde_json::to_value( + handle_session_resume(&sessions, json!(5), Some(&json!({"cwd": "/w"}))).await, + ) + .unwrap(); + assert_eq!(v["error"]["code"], json!(-32602)); + } +} From 0d3a74c13e4197f257908bb200e304dadb54648a Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 01:07:36 +0800 Subject: [PATCH 29/49] fix(acp): deliver long replies whole to avoid truncation (F2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A reply over the adapter's message limit was split into several messages, but the ACP reply route is closed after the first delivered message, so overflow chunks were dropped — a long reply truncated over ACP (verified: a 900-line reply arrived as ~413 lines). ACP is a WebSocket transport with no small per-message limit, so it now delivers replies whole: reply_message_limit() returns usize::MAX for platform "acp" (a single split_message chunk → one delivered message → full text), while every other platform keeps the adapter's chunk limit. Overflow-safe (only saturating_sub is applied). Test: ACP limit is unbounded, others unchanged, and a 50k-char reply is a single chunk. Addresses review finding F2. Co-Authored-By: Claude Opus 4.8 --- crates/openab-core/src/adapter.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/openab-core/src/adapter.rs b/crates/openab-core/src/adapter.rs index 844cefbab..88ec72b18 100644 --- a/crates/openab-core/src/adapter.rs +++ b/crates/openab-core/src/adapter.rs @@ -21,6 +21,20 @@ pub struct OutputDirectives { pub reply_to: Option, } +/// Chunk limit for delivering a reply on `platform`. ACP is a WebSocket transport with +/// no small per-message limit, and its reply route is closed after the first delivered +/// message — so splitting a long reply into multiple messages truncates it over ACP +/// (review F2). ACP therefore delivers whole (`usize::MAX` → a single chunk); every +/// other platform keeps the adapter's chunk limit. Overflow-safe: the only arithmetic on +/// the result is `saturating_sub` (mention-footer reserve). +fn reply_message_limit(platform: &str, adapter_limit: usize) -> usize { + if platform == "acp" { + usize::MAX + } else { + adapter_limit + } +} + /// Parse `[[key:value]]` directives from the beginning of agent output. /// Returns parsed directives and the remaining content (directives stripped). pub fn parse_output_directives(content: &str) -> (OutputDirectives, String) { @@ -686,7 +700,7 @@ impl AdapterRouter { ) -> Result<()> { let adapter = adapter.clone(); let thread_channel = thread_channel.clone(); - let message_limit = adapter.message_limit(); + let message_limit = reply_message_limit(&thread_channel.platform, adapter.message_limit()); let streaming = adapter.use_streaming(other_bot_present); // Keep the full turn text (incl. inter-tool narration) when streaming // (it was already shown live) OR when `[reactions] narration_display` is @@ -1686,6 +1700,18 @@ fn propagate_mentions_to_chunks( mod tests { use super::*; + #[test] + fn acp_reply_limit_is_unbounded_others_use_adapter_limit() { + // ACP delivers whole (no chunking → no truncation, review F2); other platforms + // keep the adapter's limit. + assert_eq!(reply_message_limit("acp", 4096), usize::MAX); + assert_eq!(reply_message_limit("discord", 2000), 2000); + assert_eq!(reply_message_limit("slack", 4096), 4096); + // and a long reply under the ACP limit is a single chunk (delivered whole) + let long = "x".repeat(50_000); + assert_eq!(crate::format::split_message(&long, reply_message_limit("acp", 4096)).len(), 1); + } + #[test] fn select_delivery_text_send_once_keeps_only_final_block() { // Simulates: narration "n1" → tool (answer_start→2) → narration "n2" From 279b0457c6d430e2a1acd4406a986607b4ef4565 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 12:02:49 +0800 Subject: [PATCH 30/49] fix(acp): accept baseline resource_link (F10) + validate/negotiate initialize (F8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F10 — resource_link is baseline ACP content (every agent MUST accept text + resource_link); the prior commit rejected it. extract_prompt_params now accepts resource_link and passes the link reference through as text ([name](uri) or the bare uri; missing uri → -32602) without fetching it (no SSRF). Only the capability-gated variants this agent does not advertise (image / audio / embedded resource) are rejected. F8 — handle_initialize ignored its params, always returned version 1, and marked the connection initialized unconditionally. It now deserializes the official InitializeRequest (protocolVersion required → -32602 if missing/malformed), negotiates the version (min of client and ours; a version below v1 is rejected; a higher version negotiates down to 1), responds with the negotiated version, and the dispatch marks the connection initialized only on a successful negotiation. Tests: baseline vs gated content blocks; initialize negotiation (down-negotiate, reject version 0 / missing protocolVersion / missing params). Addresses review findings F8 and F10. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 128 ++++++++++++++---- 1 file changed, 103 insertions(+), 25 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index fe713b262..803688471 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -362,8 +362,12 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { match req.method.as_str() { "initialize" => { let resp = handle_initialize(&req); + // Only mark the connection initialized when negotiation succeeded. + let negotiated_ok = resp.error.is_none(); let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); - initialized = true; + if negotiated_ok { + initialized = true; + } } "session/new" => { if !initialized { @@ -519,14 +523,33 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { fn handle_initialize(req: &JsonRpcRequest) -> JsonRpcResponse { let id = req.id.clone().unwrap_or(Value::Null); - // ACP initialize response. protocolVersion is an integer MAJOR version. - // We advertise `sessionCapabilities.resume` (we support session/resume) but - // NOT `loadSession` — the gateway cannot replay conversation history to the - // client (it lives inside the downstream agent CLI), so load is unsupported. + // Validate the official request (protocolVersion is required) before negotiating. + let init: crate::adapters::acp_schema::InitializeRequest = + match serde_json::from_value(req.params.clone().unwrap_or(Value::Null)) { + Ok(r) => r, + Err(e) => { + return JsonRpcResponse::error(id, -32602, format!("Invalid initialize params: {e}")); + } + }; + // Negotiate: respond with the version we will use = the lower of the client's and + // ours. A higher client version negotiates down to ours (the client then decides); + // a version below our minimum (v1 is the first ACP version) cannot be satisfied. + let client_version = *init.protocol_version; + let negotiated = client_version.min(ACP_PROTOCOL_VERSION as u16); + if negotiated < 1 { + return JsonRpcResponse::error( + id, + -32602, + format!("Unsupported protocolVersion {client_version}; this agent supports {ACP_PROTOCOL_VERSION}"), + ); + } + // ACP initialize response. We advertise `sessionCapabilities.resume` (we support + // session/resume) but NOT `loadSession` — the gateway cannot replay conversation + // history to the client (it lives inside the downstream agent CLI). JsonRpcResponse::success( id, json!({ - "protocolVersion": ACP_PROTOCOL_VERSION, + "protocolVersion": negotiated, "agentCapabilities": { "loadSession": false, "sessionCapabilities": { @@ -831,7 +854,7 @@ fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), Str // is rejected explicitly rather than silently dropped, so the client knows its // content was not delivered. let text = if let Some(arr) = prompt.as_array() { - let mut parts = Vec::with_capacity(arr.len()); + let mut parts: Vec = Vec::with_capacity(arr.len()); for block in arr { match block.get("type").and_then(|t| t.as_str()) { Some("text") => { @@ -839,11 +862,31 @@ fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), Str .get("text") .and_then(|t| t.as_str()) .ok_or("Text content block missing 'text'")?; - parts.push(t); + parts.push(t.to_string()); + } + Some("resource_link") => { + // Baseline ACP content (every agent MUST accept text + resource_link). + // We do not fetch the resource (that would be an SSRF risk); the link + // reference is passed through as text so the agent can act on it. + let uri = block + .get("uri") + .and_then(|v| v.as_str()) + .ok_or("resource_link content block missing 'uri'")?; + let label = block + .get("name") + .and_then(|v| v.as_str()) + .or_else(|| block.get("title").and_then(|v| v.as_str())); + parts.push(match label { + Some(l) => format!("[{l}]({uri})"), + None => uri.to_string(), + }); } Some(other) => { + // Capability-gated variants (image / audio / embedded resource) that + // this agent does not advertise in promptCapabilities are rejected + // explicitly rather than silently dropped. return Err(format!( - "Unsupported prompt content block type '{other}' — the base accepts only 'text'" + "Unsupported prompt content block type '{other}' — this agent advertises no such capability (base accepts text and resource_link)" )); } None => return Err("Prompt content block missing 'type'".into()), @@ -1101,7 +1144,7 @@ mod acp_conformance { // --- prompt content blocks (F10): unsupported block types rejected, not dropped --- #[test] - fn prompt_rejects_non_text_blocks() { + fn prompt_content_blocks_baseline_accepted_gated_rejected() { use super::extract_prompt_params; // text blocks accepted and concatenated let (_, text) = extract_prompt_params(Some(&json!({ @@ -1110,15 +1153,31 @@ mod acp_conformance { }))) .unwrap(); assert_eq!(text, "a\nb"); - // a non-text block (resource_link / image) is an explicit error, never dropped - assert!( - extract_prompt_params(Some(&json!({ - "sessionId": "sess_x", - "prompt": [{"type": "text", "text": "hi"}, {"type": "resource_link", "uri": "file:///x"}] - }))) - .is_err(), - "resource_link must be rejected, not silently dropped" - ); + // resource_link is BASELINE — accepted, rendered as a link reference (not fetched) + let (_, text) = extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [ + {"type": "text", "text": "see"}, + {"type": "resource_link", "uri": "file:///x", "name": "X"} + ] + }))) + .unwrap(); + assert_eq!(text, "see\n[X](file:///x)"); + // resource_link without a name/title renders the bare uri + let (_, text) = extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [{"type": "resource_link", "uri": "https://e/x"}] + }))) + .unwrap(); + assert_eq!(text, "https://e/x"); + // resource_link missing its required uri → error + assert!(extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [{"type": "resource_link", "name": "X"}] + }))) + .is_err()); + // capability-gated variants (image / audio / embedded resource) are rejected, + // never silently dropped assert!(extract_prompt_params(Some(&json!({ "sessionId": "sess_x", "prompt": [{"type": "image", "data": "..", "mimeType": "image/png"}] @@ -1216,15 +1275,18 @@ mod acp_handlers { Arc::new(tokio::sync::Mutex::new(HashMap::new())) } - #[test] - fn initialize_returns_conformant_capabilities() { - let req = JsonRpcRequest { + fn init_req(params: Option) -> JsonRpcRequest { + JsonRpcRequest { jsonrpc: "2.0".into(), method: "initialize".into(), id: Some(json!(1)), - params: None, - }; - let v = serde_json::to_value(handle_initialize(&req)).unwrap(); + params, + } + } + + #[test] + fn initialize_returns_conformant_capabilities() { + let v = serde_json::to_value(handle_initialize(&init_req(Some(json!({"protocolVersion": 1}))))).unwrap(); assert_eq!(v["id"], json!(1)); let result = &v["result"]; assert_eq!(result["protocolVersion"], json!(1)); @@ -1233,6 +1295,22 @@ mod acp_handlers { assert!(result["authMethods"].is_array()); } + #[test] + fn initialize_negotiates_version_and_rejects_bad() { + // a higher client version negotiates down to ours (1) + let v = serde_json::to_value(handle_initialize(&init_req(Some(json!({"protocolVersion": 5}))))).unwrap(); + assert_eq!(v["result"]["protocolVersion"], json!(1)); + // version 0 is below our minimum → -32602 + let v = serde_json::to_value(handle_initialize(&init_req(Some(json!({"protocolVersion": 0}))))).unwrap(); + assert_eq!(v["error"]["code"], json!(-32602)); + // missing protocolVersion → -32602 + let v = serde_json::to_value(handle_initialize(&init_req(Some(json!({}))))).unwrap(); + assert_eq!(v["error"]["code"], json!(-32602)); + // missing params → -32602 + let v = serde_json::to_value(handle_initialize(&init_req(None))).unwrap(); + assert_eq!(v["error"]["code"], json!(-32602)); + } + #[tokio::test] async fn session_new_mints_and_stores_a_session() { let sessions = new_sessions(); From 1be48d3b311d22af3d277f6b7084230527e8a554 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 12:11:50 +0800 Subject: [PATCH 31/49] fix(acp): fail closed off loopback without a transport key (F1/F11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACP was enabled with auth_key:None and the WS upgrade skipped validation in that state, and an empty OPENAB_ACP_AUTH_KEY was accepted as a valid key — so a config omission could expose agent execution on the default 0.0.0.0 bind. Add acp_auth_ok_for_bind(auth_key, listen_addr): a non-empty key suffices on any bind; without a key, fail-open is allowed ONLY on a loopback bind (127.0.0.0/8 / ::1 / localhost). A non-loopback bind (0.0.0.0 / LAN / LoadBalancer) without a key refuses to mount /acp — checked at both mount sites (standalone gateway serve() and embedded `openab run`). AcpConfig now treats an empty key as unset. Base ADR §2 documents the loopback fail-open policy. Test covers key/no-key × loopback/non-loopback/empty. Addresses review findings F1 and F11 (a non-loopback deployment now requires a key; the key is still accepted via header or query — query use is a documented residual for browser clients). Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 64 ++++++++++++++++++- crates/openab-gateway/src/lib.rs | 13 +++- docs/adr/acp-server-websocket-base.md | 9 ++- src/main.rs | 21 ++++-- 4 files changed, 95 insertions(+), 12 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 803688471..53b27ff8e 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -55,14 +55,54 @@ impl AcpConfig { if !enabled { return None; } - let auth_key = std::env::var("OPENAB_ACP_AUTH_KEY").ok(); + // Treat an empty value as unset (an empty string is not a usable key). + let auth_key = std::env::var("OPENAB_ACP_AUTH_KEY") + .ok() + .filter(|k| !k.is_empty()); if auth_key.is_none() { - warn!("OPENAB_ACP_AUTH_KEY not set — ACP endpoint is UNAUTHENTICATED"); + warn!( + "OPENAB_ACP_AUTH_KEY not set — /acp is only served on a loopback bind; a \ + non-loopback bind will refuse to mount it (set a key to expose it)" + ); } Some(Self { auth_key }) } } +/// Whether the listen address binds a loopback interface (`127.0.0.0/8`, `::1`, or +/// `localhost`). An unknown / unparseable host is treated as non-loopback (fail safe). +fn bind_is_loopback(listen_addr: &str) -> bool { + let host = listen_addr + .rsplit_once(':') + .map(|(h, _)| h) + .unwrap_or(listen_addr) + .trim_matches(|c| c == '[' || c == ']'); // strip IPv6 brackets + if host.eq_ignore_ascii_case("localhost") { + return true; + } + host.parse::() + .map(|ip| ip.is_loopback()) + .unwrap_or(false) +} + +/// Whether `/acp` may be mounted for the given auth key and bind address. A non-empty +/// transport key always suffices. Without a key, fail-open is permitted ONLY on a +/// loopback bind; any non-loopback bind (`0.0.0.0`, a LAN IP, a LoadBalancer) requires +/// `OPENAB_ACP_AUTH_KEY` so an unauthenticated agent endpoint is never exposed to the +/// network. Returns `Err(reason)` when the endpoint must not be mounted. +pub fn acp_auth_ok_for_bind(auth_key: Option<&str>, listen_addr: &str) -> Result<(), String> { + if auth_key.map(|k| !k.is_empty()).unwrap_or(false) { + return Ok(()); + } + if bind_is_loopback(listen_addr) { + return Ok(()); + } + Err(format!( + "OPENAB_ACP_AUTH_KEY is required to serve /acp on a non-loopback address \ + ({listen_addr}); refusing to expose an unauthenticated agent endpoint" + )) +} + /// Incremental text to stream, given the bytes already sent (`sent_len`) and the /// latest full-text snapshot. Slices via `str::get` (never byte-index `[..]`), so a /// `sent_len` that lands mid-codepoint — possible with CJK / 顏文字 / emoji only on a @@ -1187,6 +1227,26 @@ mod acp_conformance { let (_, s) = extract_prompt_params(Some(&json!({"sessionId": "sess_x", "prompt": "hello"}))).unwrap(); assert_eq!(s, "hello"); } + + // --- transport auth gate (F1): no key allowed only on loopback --- + + #[test] + fn acp_auth_gate_requires_key_off_loopback() { + use super::acp_auth_ok_for_bind; + // a non-empty key suffices on any bind + assert!(acp_auth_ok_for_bind(Some("k"), "0.0.0.0:8080").is_ok()); + assert!(acp_auth_ok_for_bind(Some("k"), "127.0.0.1:8080").is_ok()); + // no key: loopback binds are allowed + assert!(acp_auth_ok_for_bind(None, "127.0.0.1:8080").is_ok()); + assert!(acp_auth_ok_for_bind(None, "localhost:8080").is_ok()); + assert!(acp_auth_ok_for_bind(None, "[::1]:8080").is_ok()); + // no key: non-loopback binds are refused + assert!(acp_auth_ok_for_bind(None, "0.0.0.0:8080").is_err()); + assert!(acp_auth_ok_for_bind(None, "192.168.1.10:8080").is_err()); + // an empty key is treated as no key + assert!(acp_auth_ok_for_bind(Some(""), "0.0.0.0:8080").is_err()); + assert!(acp_auth_ok_for_bind(Some(""), "127.0.0.1:8080").is_ok()); + } } // --------------------------------------------------------------------------- diff --git a/crates/openab-gateway/src/lib.rs b/crates/openab-gateway/src/lib.rs index f7a92bf4d..b64a4e5e6 100644 --- a/crates/openab-gateway/src/lib.rs +++ b/crates/openab-gateway/src/lib.rs @@ -520,11 +520,18 @@ pub async fn serve(config: ServeConfig) -> anyhow::Result<()> { .route("/ws", get(ws_handler)) .route("/health", get(health)); - // ACP Server adapter + // ACP Server adapter. Fail-open (no transport key) is only allowed on a loopback + // bind; a non-loopback bind without OPENAB_ACP_AUTH_KEY refuses to mount /acp. #[cfg(feature = "acp")] if std::env::var("OPENAB_ACP_ENABLED").map(|v| v == "true" || v == "1").unwrap_or(false) { - info!("ACP server endpoint enabled at /acp"); - app = app.route("/acp", get(adapters::acp_server::ws_upgrade)); + let acp_key = std::env::var("OPENAB_ACP_AUTH_KEY").ok(); + match adapters::acp_server::acp_auth_ok_for_bind(acp_key.as_deref(), &listen_addr) { + Ok(()) => { + info!("ACP server endpoint enabled at /acp"); + app = app.route("/acp", get(adapters::acp_server::ws_upgrade)); + } + Err(e) => tracing::error!("ACP endpoint NOT mounted: {e}"), + } } // Telegram adapter diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 68076fa79..3b6aaa80b 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -37,8 +37,13 @@ ACP replies are routed back via the unified adapter's `dispatch_reply` **Two independent auth layers:** -1. **Transport** — token on the WS upgrade, timing-safe compare (`OPENAB_ACP_AUTH_KEY`; - unset ⇒ unauthenticated). +1. **Transport** — a shared bearer key on the WS upgrade (`OPENAB_ACP_AUTH_KEY`, + presented as `Authorization: Bearer ` or `?token=`, timing-safe compare via + `subtle::ConstantTimeEq`). **Fail-open only on loopback:** if no key is set, `/acp` is + mounted only when the server binds a loopback address (`127.0.0.0/8` / `::1` / + `localhost`); a non-loopback bind (`0.0.0.0`, LAN, LoadBalancer) without a key refuses + to mount the endpoint, so an unauthenticated agent endpoint is never exposed to the + network. An empty key counts as unset. 2. **Identity** — ACP events carry a fixed synthetic sender id `acp_client` and pass through the gateway trust registry (the `acp` platform is seeded there alongside telegram/line/…). Admit the sender with `GATEWAY_ALLOW_ALL_USERS=true` or diff --git a/src/main.rs b/src/main.rs index 9ca59e020..2a014979d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1130,11 +1130,22 @@ async fn main() -> anyhow::Result<()> { .map(|v| v == "true" || v == "1") .unwrap_or(false) { - info!("unified: ACP server endpoint enabled at /acp"); - app = app.route( - "/acp", - axum::routing::get(openab_gateway::adapters::acp_server::ws_upgrade), - ); + // Fail-open (no transport key) is only allowed on a loopback bind; a + // non-loopback bind without OPENAB_ACP_AUTH_KEY refuses to mount /acp. + let acp_key = std::env::var("OPENAB_ACP_AUTH_KEY").ok(); + match openab_gateway::adapters::acp_server::acp_auth_ok_for_bind( + acp_key.as_deref(), + &listen_addr, + ) { + Ok(()) => { + info!("unified: ACP server endpoint enabled at /acp"); + app = app.route( + "/acp", + axum::routing::get(openab_gateway::adapters::acp_server::ws_upgrade), + ); + } + Err(e) => error!("unified: ACP endpoint NOT mounted: {e}"), + } } let app = app.with_state(gw_state.clone()); From 99ff7f82c0d9f1828e379edf9ccff0ad1c283d1d Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 12:15:32 +0800 Subject: [PATCH 32/49] test(acp): strengthen /acp smoke into an item-by-item conformance suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/acp-ws-smoke.py now prints a grouped, item-by-item report (for pasting into the PR as evidence): Transport/Auth (token required off loopback — no-token/wrong-token rejected, valid token accepted), Protocol compliance (JSON-RPC envelope + ACP wire shapes, initialize negotiation, session lifecycle, session/update notification shape, snake_case stopReason, resume), and Protocol edge cases (version negotiation & -32602 rejects, required-param validation, -32002 not-initialized, -32600 bad jsonrpc, resource_link accepted / image rejected, notification silence, F2 oversized-reply whole delivery, Unicode/emoji stream integrity). OPENAB_ACP_TOKEN is now mandatory. Updates canary-tests.md accordingly. Note: several checks require this branch deployed (they exercise F8/F9/F10/F2/F1) and a transport key, so the suite is green only after a redeploy with a token. Co-Authored-By: Claude Opus 4.8 --- docs/canary-tests.md | 15 +- scripts/acp-ws-smoke.py | 367 ++++++++++++++++++++++++++-------------- 2 files changed, 253 insertions(+), 129 deletions(-) diff --git a/docs/canary-tests.md b/docs/canary-tests.md index 7656c5502..01b41bec8 100644 --- a/docs/canary-tests.md +++ b/docs/canary-tests.md @@ -150,16 +150,21 @@ For an ACP adapter change, use a minimal bidirectional JSON-RPC client to exerci ### WebSocket transport (`/acp`) -OpenAB also serves ACP over a WebSocket (`GET /acp`, feature `acp` + `OPENAB_ACP_ENABLED`) — the upstream client↔gateway hop, distinct from the downstream stdio hop below. `scripts/acp-ws-smoke.py` is a ready-to-run client for it: it drives `initialize → session/new → session/prompt` (stream + `stopReason`) `→ session/resume`, and confirms OpenAB slash-command replies (`/model`, `/reset`) render back over ACP. It needs a live deployment (the prompt turns hit the real model). +OpenAB also serves ACP over a WebSocket (`GET /acp`, feature `acp` + `OPENAB_ACP_ENABLED`) — the upstream client↔gateway hop, distinct from the downstream stdio hop below. `scripts/acp-ws-smoke.py` is a ready-to-run **conformance suite** for it that prints an item-by-item report (paste it into the PR as evidence), in three groups: + +- **Transport / Auth** — a transport token is required off loopback: no-token and wrong-token connections are rejected, the valid token is accepted. +- **Protocol compliance** — JSON-RPC envelope + ACP wire shapes: initialize negotiation, `session/new` / `session/prompt` (streamed `session/update` `agent_message_chunk` + snake_case `stopReason`) / `session/resume`. +- **Protocol edge cases** — version negotiation & rejects (`-32602`), required-param validation, not-initialized (`-32002`), bad JSON-RPC version (`-32600`), content-block policy (`resource_link` accepted, gated `image` rejected), notification silence, oversized-reply whole delivery, and Unicode/emoji stream integrity. + +It needs a live deployment (prompt turns hit the real model) and a transport token. ```bash -# default ws://localhost:8080/acp; pass another URL as $1 -uv run scripts/acp-ws-smoke.py ws://:8080/acp -# if the endpoint sets OPENAB_ACP_AUTH_KEY: +# WS_URL defaults to ws://localhost:8080/acp; pass another URL as $1. +# OPENAB_ACP_TOKEN is MANDATORY — the endpoint requires a transport key off loopback. OPENAB_ACP_TOKEN= uv run scripts/acp-ws-smoke.py ws://:8080/acp ``` -Exits non-zero unless all checks pass. For the in-repo `cargo test` counterpart (offline wire-conformance of the same payloads against the generated types), see the `acp_conformance` module in `crates/openab-gateway/src/adapters/acp_server.rs`. +Exits non-zero unless every check passes. For the in-repo `cargo test` counterpart (offline wire-conformance + handler-level + streaming tests), see the `acp_conformance`, `acp_handlers`, and `acp_streaming` modules in `crates/openab-gateway/src/adapters/acp_server.rs`. ### Transport Method diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py index a224ec77b..4578f1b17 100755 --- a/scripts/acp-ws-smoke.py +++ b/scripts/acp-ws-smoke.py @@ -4,33 +4,29 @@ # dependencies = ["websockets>=12"] # /// """ -ACP-over-WebSocket smoke test — upstream client<->gateway `/acp` hop. +ACP-over-WebSocket conformance suite — upstream client<->gateway `/acp` hop. -This exercises the WebSocket ACP server this PR adds (GET /acp on the openab -gateway / embedded `openab run`), which is a different boundary from the -downstream core<->agent-CLI stdio hop covered by docs/canary-tests.md Layer 2. -It drives a real deployment end to end, so a live agent backend is required — -the prompt turns hit the actual model. +Exercises the WebSocket ACP server this PR adds (GET /acp on the openab gateway / +embedded `openab run`) against a LIVE deployment, and prints an item-by-item report +suitable for pasting into the PR as evidence. It covers three groups: + + [Transport / Auth] — a transport token is REQUIRED off loopback: no-token and + wrong-token connections are rejected, the valid token is accepted. + [Protocol compliance] — JSON-RPC envelope + ACP wire shapes (initialize negotiation, + session lifecycle, session/update notification, stopReason, resume). + [Protocol edge cases] — hardening: version negotiation & rejects, param validation, + content-block policy, notification silence, oversized-reply whole + delivery, and Unicode/emoji stream integrity. + +A live agent backend is required (prompt turns hit the real model). Usage: - uv run scripts/acp-ws-smoke.py [WS_URL] - ACP_URL=ws://host:8080/acp uv run scripts/acp-ws-smoke.py - - # default WS_URL: ws://localhost:8080/acp - # if the endpoint sets OPENAB_ACP_AUTH_KEY, pass the token: - OPENAB_ACP_TOKEN= uv run scripts/acp-ws-smoke.py ws://host:8080/acp - -Checks (exit 0 iff all pass, else 2): - 1. initialize -> protocolVersion == 1 and agentCapabilities present - 2. session/new -> { sessionId: sess_... } - 3. session/prompt -> agent_message_chunk stream is non-empty - 4. session/prompt -> response stopReason == "end_turn" - 5. session/resume -> {} (no error, no history replay) - 6. "/model" as a prompt -> the config-command reply renders back over ACP - 7. "/reset" as a prompt -> the session-command reply renders back over ACP - -Checks 6-7 confirm OpenAB slash-command replies reach the ACP client stream -(they arrive as agent_message_chunk), i.e. command parity over ACP. + OPENAB_ACP_TOKEN= uv run scripts/acp-ws-smoke.py ws://:8080/acp + + # WS_URL defaults to ws://localhost:8080/acp + # OPENAB_ACP_TOKEN is MANDATORY — the endpoint requires a transport key off loopback. + +Exit code 0 iff every check passes. """ import asyncio import json @@ -38,119 +34,242 @@ import sys import websockets +from websockets.exceptions import InvalidStatus, InvalidStatusCode, WebSocketException +BASE_URL = sys.argv[1] if len(sys.argv) > 1 else os.environ.get("ACP_URL", "ws://localhost:8080/acp") +TOKEN = os.environ.get("OPENAB_ACP_TOKEN") -def build_url() -> str: - url = sys.argv[1] if len(sys.argv) > 1 else os.environ.get("ACP_URL", "ws://localhost:8080/acp") - token = os.environ.get("OPENAB_ACP_TOKEN") - if token: - sep = "&" if "?" in url else "?" - url = f"{url}{sep}token={token}" - return url +results: list[tuple[str, bool, str]] = [] -results: list[tuple[bool, str]] = [] +def record(section: str, ok: bool, name: str, detail: str = "") -> None: + results.append((section, ok, name)) + mark = "PASS" if ok else "FAIL" + line = f" [{mark}] {name}" + if detail: + line += f" — {detail}" + print(line, flush=True) -def check(ok: bool, name: str, detail: str = "") -> None: - results.append((ok, name)) - mark = "PASS" if ok else "FAIL" - print(f" [{mark}] {name}{(' — ' + detail) if detail else ''}", flush=True) +def url_with_token(token: str | None) -> str: + if not token: + return BASE_URL + sep = "&" if "?" in BASE_URL else "?" + return f"{BASE_URL}{sep}token={token}" -async def main() -> int: - url = build_url() - redacted = url.split("token=")[0] + "token=" if "token=" in url else url - print(f"ACP WS smoke → {redacted}", flush=True) - - async with websockets.connect(url, open_timeout=8, max_size=None) as ws: - next_id = 0 - - async def call(method, params=None, timeout=8): - """Send a JSON-RPC request; collect streamed notifications until the - response with the matching id arrives (or timeout).""" - nonlocal next_id - next_id += 1 - req_id = next_id - msg = {"jsonrpc": "2.0", "id": req_id, "method": method} - if params is not None: - msg["params"] = params - await ws.send(json.dumps(msg)) - chunks: list[str] = [] - notifs: list[str] = [] - while True: - try: - raw = await asyncio.wait_for(ws.recv(), timeout=timeout) - except asyncio.TimeoutError: - return {"_timeout": True, "chunks": chunks, "notifs": notifs} - m = json.loads(raw) - if m.get("method") == "session/update": - update = m.get("params", {}).get("update", {}) - if update.get("sessionUpdate") == "agent_message_chunk": - chunks.append(update.get("content", {}).get("text", "")) - else: - notifs.append(update.get("sessionUpdate")) - continue - if m.get("method"): # other server->client notification - notifs.append(m.get("method")) - continue - if m.get("id") == req_id: - m["chunks"] = chunks - m["notifs"] = notifs - return m - - # 1. initialize - r = await call("initialize", {"protocolVersion": 1, "clientInfo": {"name": "acp-ws-smoke", "version": "0"}}) +async def try_connect(token: str | None): + """Return an open ws (caller closes) or raise on rejection.""" + return await websockets.connect(url_with_token(token), open_timeout=8, max_size=None) + + +class Conn: + """A JSON-RPC/ACP client over one WebSocket connection.""" + + def __init__(self, ws): + self.ws = ws + self._id = 0 + + async def call(self, method, params=None, *, notification=False, timeout=8): + """Send a request (or notification) and, for requests, gather streamed + notifications until the response with the matching id arrives.""" + msg = {"jsonrpc": "2.0", "method": method} + rid = None + if not notification: + self._id += 1 + rid = self._id + msg["id"] = rid + if params is not None: + msg["params"] = params + await self.ws.send(json.dumps(msg)) + chunks, notes = [], [] + if notification: + return {"_notification": True} + while True: + try: + raw = await asyncio.wait_for(self.ws.recv(), timeout=timeout) + except asyncio.TimeoutError: + return {"_timeout": True, "chunks": chunks, "notes": notes} + m = json.loads(raw) + if m.get("method") == "session/update": + notes.append(m) + u = m.get("params", {}).get("update", {}) + if u.get("sessionUpdate") == "agent_message_chunk": + chunks.append(u.get("content", {}).get("text", "")) + continue + if m.get("method"): + notes.append(m) + continue + if m.get("id") == rid: + m["chunks"] = chunks + m["notes"] = notes + return m + + async def initialize(self, version=1): + return await self.call("initialize", {"protocolVersion": version, "clientInfo": {"name": "conf", "version": "0"}}) + + async def new_session(self): + r = await self.call("session/new", {"cwd": "/home/agent", "mcpServers": []}) + return r.get("result", {}).get("sessionId", "") + + +async def expect_silence(conn: Conn, method, params, timeout=3) -> bool: + """Send a notification (no id) and assert the server sends nothing back.""" + await conn.call(method, params, notification=True) + try: + await asyncio.wait_for(conn.ws.recv(), timeout=timeout) + return False # got a frame → not silent + except asyncio.TimeoutError: + return True + + +# --------------------------------------------------------------------------- # +# Sections +# --------------------------------------------------------------------------- # +async def section_auth(): + print("\n[Transport / Auth] — a transport token is REQUIRED", flush=True) + # no token → rejected + try: + ws = await try_connect(None) + await ws.close() + record("auth", False, "connection WITHOUT a token is rejected", "connection was accepted") + except (InvalidStatus, InvalidStatusCode, WebSocketException, OSError) as e: + record("auth", True, "connection WITHOUT a token is rejected", type(e).__name__) + # wrong token → rejected + try: + ws = await try_connect("wrong-" + (TOKEN or "x")) + await ws.close() + record("auth", False, "connection with a WRONG token is rejected", "connection was accepted") + except (InvalidStatus, InvalidStatusCode, WebSocketException, OSError) as e: + record("auth", True, "connection with a WRONG token is rejected", type(e).__name__) + # valid token → accepted + try: + ws = await try_connect(TOKEN) + await ws.close() + record("auth", True, "connection with the VALID token is accepted") + except Exception as e: # noqa: BLE001 + record("auth", False, "connection with the VALID token is accepted", repr(e)) + + +async def section_compliance(): + print("\n[Protocol compliance] — JSON-RPC envelope + ACP wire shapes", flush=True) + async with await try_connect(TOKEN) as ws: + c = Conn(ws) + r = await c.initialize() res = r.get("result", {}) - check( - res.get("protocolVersion") == 1 and "agentCapabilities" in res, - "initialize", - f"protocolVersion={res.get('protocolVersion')} caps={list(res.get('agentCapabilities', {}).keys())}", - ) - - # 2. session/new - r = await call("session/new", {"cwd": "/home/agent", "mcpServers": []}) - sid = r.get("result", {}).get("sessionId", "") - check(sid.startswith("sess_"), "session/new", f"sessionId={sid[:20]}…") - - # 3./4. session/prompt — stream + stopReason (hits the live model) - r = await call( - "session/prompt", - {"sessionId": sid, "prompt": [{"type": "text", "text": "Reply with exactly one word: PONG"}]}, - timeout=90, - ) - stream = "".join(r.get("chunks", [])) - stop_reason = r.get("result", {}).get("stopReason") - check(len(stream) > 0, "prompt → agent_message_chunk stream", f"{len(stream)} chars: {stream[:40]!r}") - check(stop_reason == "end_turn", "prompt → stopReason", f"stopReason={stop_reason}") - - # 5. session/resume - r = await call("session/resume", {"sessionId": sid, "cwd": "/home/agent", "mcpServers": []}) - check("result" in r and not r.get("error"), "session/resume", f"result={r.get('result')}") - - # 6. /model — config command reply renders back over ACP. - # A JSON-RPC error or a timeout is a FAILURE, not a pass: a check passes only - # on a real rendered reply (chunks present with the expected text). - r = await call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "/model"}]}, timeout=30) + record("comp", r.get("jsonrpc") == "2.0" and r.get("id") == 1, "initialize: response is JSON-RPC 2.0 with correlated id") + record("comp", res.get("protocolVersion") == 1 and isinstance(res.get("protocolVersion"), int), + "initialize: protocolVersion is the integer 1", f"got {res.get('protocolVersion')!r}") + caps = res.get("agentCapabilities", {}) + ok_caps = caps.get("loadSession") is False and isinstance(caps.get("sessionCapabilities", {}).get("resume"), dict) and "promptCapabilities" in caps + record("comp", ok_caps, "initialize: agentCapabilities shape (loadSession:false, sessionCapabilities.resume, promptCapabilities)") + record("comp", isinstance(res.get("authMethods"), list), "initialize: authMethods is an array") + + sid = await c.new_session() + record("comp", sid.startswith("sess_"), "session/new: returns { sessionId: sess_ }", sid[:24]) + + r = await c.call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "Reply with exactly one word: PONG"}]}, timeout=90) + upd = next((n for n in r.get("notes", []) if n.get("method") == "session/update"), None) + u = (upd or {}).get("params", {}).get("update", {}) + record("comp", u.get("sessionUpdate") == "agent_message_chunk" and u.get("content", {}).get("type") == "text", + "session/prompt: streams session/update {sessionUpdate:agent_message_chunk, content.type:text}") + record("comp", r.get("result", {}).get("stopReason") == "end_turn", + "session/prompt: response stopReason is snake_case end_turn", f"got {r.get('result', {}).get('stopReason')!r}") + + r = await c.call("session/resume", {"sessionId": sid, "cwd": "/home/agent", "mcpServers": []}) + record("comp", r.get("result") == {} and not r.get("error"), "session/resume: returns {} (no history replay)") + + +async def section_edges(): + print("\n[Protocol edge cases] — negotiation, validation, content policy, hardening", flush=True) + # initialize negotiation + rejects (fresh connections; these do not need init state) + async with await try_connect(TOKEN) as ws: + c = Conn(ws) + r = await c.initialize(version=5) + record("edge", r.get("result", {}).get("protocolVersion") == 1, "initialize: client protocolVersion 5 negotiates down to 1") + async with await try_connect(TOKEN) as ws: + r = await Conn(ws).initialize(version=0) + record("edge", r.get("error", {}).get("code") == -32602, "initialize: protocolVersion 0 rejected (-32602)") + async with await try_connect(TOKEN) as ws: + r = await Conn(ws).call("initialize", {"clientInfo": {"name": "x"}}) + record("edge", r.get("error", {}).get("code") == -32602, "initialize: missing protocolVersion rejected (-32602)") + + # lifecycle: session/new before initialize → -32002 + async with await try_connect(TOKEN) as ws: + r = await Conn(ws).call("session/new", {"cwd": "/w", "mcpServers": []}) + record("edge", r.get("error", {}).get("code") == -32002, "session/new before initialize rejected (-32002)") + + # bad jsonrpc version → -32600 + async with await try_connect(TOKEN) as ws: + await ws.send(json.dumps({"jsonrpc": "1.0", "id": 1, "method": "initialize", "params": {"protocolVersion": 1}})) + m = json.loads(await asyncio.wait_for(ws.recv(), timeout=8)) + record("edge", m.get("error", {}).get("code") == -32600, "jsonrpc != \"2.0\" rejected (-32600)") + + # the rest run on one initialized connection + async with await try_connect(TOKEN) as ws: + c = Conn(ws) + await c.initialize() + # param validation + r = await c.call("session/new", {"mcpServers": []}) + record("edge", r.get("error", {}).get("code") == -32602, "session/new missing cwd rejected (-32602)") + r = await c.call("session/resume", {"cwd": "/w", "mcpServers": []}) + record("edge", r.get("error", {}).get("code") == -32602, "session/resume missing sessionId rejected (-32602)") + + sid = await c.new_session() + # content-block policy: resource_link accepted (baseline), image rejected (gated) + r = await c.call("session/prompt", {"sessionId": sid, "prompt": [ + {"type": "text", "text": "ignore the link, just reply OK"}, + {"type": "resource_link", "uri": "file:///x", "name": "X"}, + ]}, timeout=90) + record("edge", not r.get("error"), "prompt: resource_link content accepted (ACP baseline)") + r = await c.call("session/prompt", {"sessionId": sid, "prompt": [ + {"type": "image", "data": "..", "mimeType": "image/png"}, + ]}) + record("edge", r.get("error", {}).get("code") == -32602, "prompt: image content rejected (-32602, capability not advertised)") + + # notification silence: session/cancel as a notification gets no response + silent = await expect_silence(c, "session/cancel", {"sessionId": sid}) + record("edge", silent, "notification (session/cancel, no id) receives no response") + + # F2 — an oversized reply (> the 4096 unified message limit) arrives whole + r = await c.call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": + "Output the lines 'LINE 0001' through 'LINE 0600', one per line, zero-padded to 4 digits, nothing else."}]}, timeout=180) text = "".join(r.get("chunks", [])) - check( - not r.get("error") and not r.get("_timeout") and bool(r.get("chunks")) and "model" in text.lower(), - "/model reply renders back to ACP", - f"chunks={len(r.get('chunks', []))} err={r.get('error')} timeout={r.get('_timeout', False)} body={text[:60]!r}", - ) - - # 7. /reset — session command reply renders back over ACP. - r = await call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "/reset"}]}, timeout=30) + import re + nums = [int(x) for x in re.findall(r"LINE (\d{4})", text)] + record("edge", len(text) > 4096 and max(nums or [0]) >= 550, + "F2: oversized reply delivered whole (not truncated at message limit)", f"{len(text)} chars, max LINE {max(nums or [0]):04d}") + + # Unicode / emoji stream integrity + r = await c.call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": + "Reply with exactly this and nothing else: 你好 🎉 👨‍👩‍👧‍👦 ❤️"}]}, timeout=90) text = "".join(r.get("chunks", [])) - check( - not r.get("error") and not r.get("_timeout") and bool(r.get("chunks")) and "reset" in text.lower(), - "/reset reply renders back to ACP", - f"chunks={len(r.get('chunks', []))} err={r.get('error')} timeout={r.get('_timeout', False)} body={text[:60]!r}", - ) + record("edge", "🎉" in text and "👨‍👩‍👧‍👦" in text or "👨" in text, + "CJK + emoji (ZWJ family) stream intact", repr(text[:40])) + + +async def main() -> int: + if not TOKEN: + print("ERROR: OPENAB_ACP_TOKEN is required (the /acp endpoint mandates a transport token off loopback).", file=sys.stderr) + return 3 + print(f"ACP conformance suite → {BASE_URL}", flush=True) + await section_auth() + await section_compliance() + await section_edges() - passed = sum(1 for ok, _ in results if ok) total = len(results) - print(f"\nRESULT: {passed}/{total} passed", flush=True) + passed = sum(1 for _, ok, _ in results if ok) + by_section = {} + for sec, ok, _ in results: + s = by_section.setdefault(sec, [0, 0]) + s[1] += 1 + if ok: + s[0] += 1 + print("\n" + "-" * 60, flush=True) + labels = {"auth": "Transport / Auth", "comp": "Protocol compliance", "edge": "Protocol edge cases"} + for sec, (p, t) in by_section.items(): + print(f" {labels.get(sec, sec):22} {p}/{t}", flush=True) + print(f"\nRESULT: {passed}/{total} checks passed", flush=True) return 0 if passed == total else 2 From 560e5a70ed2bf5253097eb148cf661d596c52ad9 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 17:32:47 +0800 Subject: [PATCH 33/49] feat(acp): carry the transport bearer key via Sec-WebSocket-Protocol (F11) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The token was accepted via `Authorization: Bearer` or a `?token=` query. Browsers can't set an Authorization header on a WS handshake, so they fell back to `?token=`, which leaks the key into URLs/access logs/history (F11). Add the subprotocol path: a client offers `Sec-WebSocket-Protocol: openab.bearer., acp.v1`; ws_upgrade extracts the key from the `openab.bearer.` entry (timing-safe compare as before) and echoes the real `acp.v1` subprotocol so the browser handshake completes. This keeps the key out of the URL — the de facto browser-WS bearer pattern (Kubernetes API server). Priority: Authorization header → subprotocol → `?token=` (legacy/deprecated). We deliberately do NOT repurpose ACP's authenticate/authMethods (agent→provider auth, credential out-of-band — not client→server); authMethods stays []. ADR §2 documents the methodology and rationale; the conformance suite authenticates via the subprotocol. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 51 ++++++++++++++++++- docs/adr/acp-server-websocket-base.md | 31 ++++++++--- scripts/acp-ws-smoke.py | 13 ++--- 3 files changed, 81 insertions(+), 14 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 53b27ff8e..280a94c4d 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -39,6 +39,30 @@ const MAX_FRAME_BYTES: usize = 1 << 20; // 1 MiB per inbound JSON-RPC frame /// JSON-RPC implementation-defined server error for a hit resource cap. const ACP_OVERLOADED: i32 = -32000; +/// WebSocket subprotocol prefix that carries the bearer token from a browser client +/// (browsers cannot set an `Authorization` header on a WS handshake, but they CAN offer +/// subprotocols via `new WebSocket(url, protocols)`). The client offers +/// `Sec-WebSocket-Protocol: openab.bearer., acp.v1`; the server extracts the token +/// and echoes the real `acp.v1` subprotocol so the handshake completes. This keeps the +/// token OUT of the URL — the de facto browser-WS bearer pattern (as used by the +/// Kubernetes API server). Non-browser clients should prefer `Authorization: Bearer`. +const BEARER_SUBPROTOCOL_PREFIX: &str = "openab.bearer."; +/// The real ACP subprotocol echoed back on a successful upgrade. +const ACP_SUBPROTOCOL: &str = "acp.v1"; + +/// Extract the bearer token from a `Sec-WebSocket-Protocol` offer (the +/// `openab.bearer.` entry), if present. +fn subprotocol_token(headers: &axum::http::HeaderMap) -> Option<&str> { + headers + .get("sec-websocket-protocol") + .and_then(|v| v.to_str().ok()) + .and_then(|list| { + list.split(',') + .map(str::trim) + .find_map(|p| p.strip_prefix(BEARER_SUBPROTOCOL_PREFIX)) + }) +} + // --------------------------------------------------------------------------- // ACP Configuration // --------------------------------------------------------------------------- @@ -259,11 +283,16 @@ pub async fn ws_upgrade( headers: axum::http::HeaderMap, ws: WebSocketUpgrade, ) -> axum::response::Response { - // Auth: Bearer token from Authorization header or ?token= query param + // Bearer token, in priority order: + // 1. `Authorization: Bearer ` — non-browser clients (cleanest). + // 2. `Sec-WebSocket-Protocol: openab.bearer., acp.v1` — browsers (keeps the + // token out of the URL; the de facto browser-WS bearer pattern). + // 3. `?token=` query — legacy fallback; leaks in URLs/logs, deprecated. let token = headers .get("authorization") .and_then(|v| v.to_str().ok()) .and_then(|v| v.strip_prefix("Bearer ")) + .or_else(|| subprotocol_token(&headers)) .or_else(|| query.get("token").map(|s| s.as_str())); let expected = state.acp.as_ref().and_then(|c| c.auth_key.as_ref()); @@ -282,7 +311,11 @@ pub async fn ws_upgrade( } } - ws.on_upgrade(move |socket| handle_acp_connection(state, socket)) + // Echo the `acp.v1` subprotocol so a browser that offered it (alongside its + // `openab.bearer.` entry) completes the handshake. Clients that offer no + // subprotocol are unaffected. + ws.protocols([ACP_SUBPROTOCOL]) + .on_upgrade(move |socket| handle_acp_connection(state, socket)) } // --------------------------------------------------------------------------- @@ -1247,6 +1280,20 @@ mod acp_conformance { assert!(acp_auth_ok_for_bind(Some(""), "0.0.0.0:8080").is_err()); assert!(acp_auth_ok_for_bind(Some(""), "127.0.0.1:8080").is_ok()); } + + #[test] + fn subprotocol_token_extraction() { + use super::subprotocol_token; + use axum::http::HeaderMap; + let mut h = HeaderMap::new(); + assert_eq!(subprotocol_token(&h), None); // no header + // the browser offers "openab.bearer., acp.v1" → extract the token + h.insert("sec-websocket-protocol", "openab.bearer.abc123, acp.v1".parse().unwrap()); + assert_eq!(subprotocol_token(&h), Some("abc123")); + // only the real protocol, no bearer entry → None + h.insert("sec-websocket-protocol", "acp.v1".parse().unwrap()); + assert_eq!(subprotocol_token(&h), None); + } } // --------------------------------------------------------------------------- diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 3b6aaa80b..bcaeb9b52 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -38,12 +38,31 @@ ACP replies are routed back via the unified adapter's `dispatch_reply` **Two independent auth layers:** 1. **Transport** — a shared bearer key on the WS upgrade (`OPENAB_ACP_AUTH_KEY`, - presented as `Authorization: Bearer ` or `?token=`, timing-safe compare via - `subtle::ConstantTimeEq`). **Fail-open only on loopback:** if no key is set, `/acp` is - mounted only when the server binds a loopback address (`127.0.0.0/8` / `::1` / - `localhost`); a non-loopback bind (`0.0.0.0`, LAN, LoadBalancer) without a key refuses - to mount the endpoint, so an unauthenticated agent endpoint is never exposed to the - network. An empty key counts as unset. + timing-safe compare via `subtle::ConstantTimeEq`). ACP itself defines **no** + client→server transport auth (its reference transport is a local stdio subprocess, so + the OS process boundary is the trust boundary); running ACP over a network is outside + that model, so the transport key is an OpenAB addition. The key is presented, in + priority order: + 1. **`Authorization: Bearer `** — non-browser clients (cleanest). + 2. **`Sec-WebSocket-Protocol: openab.bearer., acp.v1`** — the **browser** path: + browsers cannot set an `Authorization` header on a WS handshake but can offer + subprotocols via `new WebSocket(url, protocols)`. The server extracts the key from + the `openab.bearer.` entry and echoes the real `acp.v1` subprotocol. This is the de + facto browser-WS bearer pattern (as used by the Kubernetes API server) and keeps the + key **out of the URL**. + 3. **`?token=`** query — legacy fallback only; the key leaks into URLs / access + logs / history, so it is deprecated in favor of the subprotocol. + + We deliberately do **not** repurpose ACP's `authenticate` / `authMethods` for this: + those are agent→provider auth (the client helping a locally-spawned agent log in to its + LLM, credential set out-of-band), not client→server, so a standard ACP client would + misread them. `authMethods` stays `[]`. + + **Fail-open only on loopback:** if no key is set, `/acp` is mounted only when the server + binds a loopback address (`127.0.0.0/8` / `::1` / `localhost`); a non-loopback bind + (`0.0.0.0`, LAN, LoadBalancer) without a key refuses to mount the endpoint, so an + unauthenticated agent endpoint is never exposed to the network. An empty key counts as + unset. 2. **Identity** — ACP events carry a fixed synthetic sender id `acp_client` and pass through the gateway trust registry (the `acp` platform is seeded there alongside telegram/line/…). Admit the sender with `GATEWAY_ALLOW_ALL_USERS=true` or diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py index 4578f1b17..4a8a61bd9 100755 --- a/scripts/acp-ws-smoke.py +++ b/scripts/acp-ws-smoke.py @@ -51,16 +51,17 @@ def record(section: str, ok: bool, name: str, detail: str = "") -> None: print(line, flush=True) -def url_with_token(token: str | None) -> str: - if not token: - return BASE_URL - sep = "&" if "?" in BASE_URL else "?" - return f"{BASE_URL}{sep}token={token}" +def bearer_subprotocols(token: str | None) -> list[str]: + # Carry the token via the Sec-WebSocket-Protocol subprotocol (keeps it out of the + # URL — the de facto browser-WS bearer pattern). The server echoes `acp.v1`. + return [f"openab.bearer.{token}", "acp.v1"] if token else ["acp.v1"] async def try_connect(token: str | None): """Return an open ws (caller closes) or raise on rejection.""" - return await websockets.connect(url_with_token(token), open_timeout=8, max_size=None) + return await websockets.connect( + BASE_URL, subprotocols=bearer_subprotocols(token), open_timeout=8, max_size=None + ) class Conn: From 7e07622895e41a47ced05cdb0244739fe064a551 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 18:03:35 +0800 Subject: [PATCH 34/49] =?UTF-8?q?docs(acp):=20flesh=20out=20the=20tool=5Fc?= =?UTF-8?q?all=20display=20roadmap=20item=20(=C2=A76)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record the finding that downstream tool events currently reach the ACP client only merged into the reply text (openab-core compose_display prepends '🔧 …' lines), and the recommended approach: for the acp platform, tap AcpEvent::ToolStart/ToolDone before the merge and emit structured session/update tool_call/tool_call_update notifications so clients render tool chips distinctly (ACP-native, Zed-compatible). Doc-only. Co-Authored-By: Claude Opus 4.8 --- docs/adr/acp-server-websocket-base.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index bcaeb9b52..535e428c8 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -195,8 +195,19 @@ North star: the agent's LLM autonomously operating the user's real browser (gene against real traffic first). ### Optional (as-needed, off the critical path) -- richer `session/update` variants: `tool_call` / `tool_call_update` (display), - `agent_thought_chunk` / `plan` / `available_commands_update` / `usage_update` +- **`tool_call` / `tool_call_update` display** — a client-facing tool-activity display + (e.g. a distinct "tool chip" per call with running/done/failed state). *State today:* the + downstream tool events reach the ACP client only **merged into the text** — `openab-core` + parses them into `AcpEvent::ToolStart` / `ToolDone`, then `compose_display` prepends + "🔧 …" lines onto the reply text buffer that streams as `agent_message_chunk`; there is + no structured separation over `/acp`. *Recommended approach:* for the `acp` platform, tap + the `AcpEvent::ToolStart` / `ToolDone` stream **before** the `compose_display` merge and + emit structured `session/update` `tool_call` / `tool_call_update` notifications (with + `toolCallId` / `title` / `status`) separately from the text — this is the ACP-native path + (standard clients like Zed render it too), avoids brittle client-side text parsing, and + cleanly separates tool activity from the answer. Client (extension) then renders chips. +- other richer `session/update` variants: `agent_thought_chunk` / `plan` / + `available_commands_update` / `usage_update` - `fs/*`, `terminal/*` (sibling agent→client capabilities) - `ContentBlock` image / audio / resource (image only if screenshot-based browser tools) - session admin: `session/close` / `list` / `delete`, `set_mode` / `set_config_option`, From a53f6821115f0e4e4347e3e6f9d1372ea8c90c12 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 18:13:54 +0800 Subject: [PATCH 35/49] fix(acp): validate JSON-RPC id type (F13), close oversized frames (F7), redact session logs (F12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - F13: reject a request whose `id` is not a string / number / null (object/array/bool) with -32600, per JSON-RPC. Conformance suite adds an id-object check. - F7: an oversized inbound frame can't be parsed, so we can't tell request from notification or recover its id — stop fabricating a JSON-RPC error (which broke notification silence) and close the connection as a transport-level violation. - F12: the session lifecycle logs (created / resumed / prompt dispatched) carried the sessionId (a resume capability; the channel_id shares its uuid) at info!; downgraded to debug! so the capability stays out of normal logs. Connection-level info! is unchanged. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 38 ++++++++++++++----- scripts/acp-ws-smoke.py | 6 +++ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 280a94c4d..fe4a6ed94 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -362,15 +362,18 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { continue; }; - // Bound inbound frame size before parsing (deterministic overload, not OOM). + // Bound inbound frame size before parsing. An oversized frame can't be parsed, + // so we can't tell request from notification or recover its id — do NOT fabricate + // a JSON-RPC response (which would violate notification silence). Treat it as a + // transport-level violation: log and close the connection. if text.len() > MAX_FRAME_BYTES { - let resp = JsonRpcResponse::error( - Value::Null, - ACP_OVERLOADED, - format!("Frame too large ({} bytes; max {MAX_FRAME_BYTES})", text.len()), + warn!( + connection = %connection_id, + bytes = text.len(), + max = MAX_FRAME_BYTES, + "ACP frame too large; closing connection" ); - let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); - continue; + break; } if trace { @@ -393,6 +396,20 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { // `None`, so notification detection uses raw key PRESENCE on the parsed JSON. let is_notification = raw.get("id").is_none(); + // JSON-RPC: `id`, when present, MUST be a string, number, or null — never an + // object, array, or boolean. Reject a wrong-typed id as an Invalid Request. + if let Some(id) = raw.get("id") { + if !(id.is_string() || id.is_number() || id.is_null()) { + let err_resp = JsonRpcResponse::error( + Value::Null, + -32600, + "Invalid Request: id must be a string, number, or null", + ); + let _ = out_tx.send(serde_json::to_string(&err_resp).unwrap()); + continue; + } + } + let req: JsonRpcRequest = match serde_json::from_value(raw) { Ok(r) => r, Err(e) => { @@ -663,7 +680,8 @@ async fn handle_session_new( }, ); - info!(session = %session_id, "ACP session created"); + // Downgraded from info! — sessionId is a resume capability; keep it out of normal logs (F12). + debug!(session = %session_id, "ACP session created"); // ACP session/new response is just { sessionId }. JsonRpcResponse::success(id, json!({ "sessionId": session_id })) @@ -714,7 +732,7 @@ async fn handle_session_resume( }, ); - info!(session = %session_id, "ACP session resumed"); + debug!(session = %session_id, "ACP session resumed"); // ACP session/resume response is an empty object (no history replay). JsonRpcResponse::success(id, json!({})) @@ -844,7 +862,7 @@ async fn handle_session_prompt( } } - info!(session = %session_id, channel = %channel_id, "ACP: prompt dispatched"); + debug!(session = %session_id, channel = %channel_id, "ACP: prompt dispatched"); // Stream replies back as ACP `session/update` notifications. let mut sent_len = 0usize; diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py index 4a8a61bd9..b38053080 100755 --- a/scripts/acp-ws-smoke.py +++ b/scripts/acp-ws-smoke.py @@ -206,6 +206,12 @@ async def section_edges(): m = json.loads(await asyncio.wait_for(ws.recv(), timeout=8)) record("edge", m.get("error", {}).get("code") == -32600, "jsonrpc != \"2.0\" rejected (-32600)") + # wrong-typed JSON-RPC id (object) → -32600 + async with await try_connect(TOKEN) as ws: + await ws.send(json.dumps({"jsonrpc": "2.0", "id": {}, "method": "initialize", "params": {"protocolVersion": 1}})) + m = json.loads(await asyncio.wait_for(ws.recv(), timeout=8)) + record("edge", m.get("error", {}).get("code") == -32600, "wrong-typed id (object) rejected (-32600)") + # the rest run on one initialized connection async with await try_connect(TOKEN) as ws: c = Conn(ws) From 45375e98ffdc1e4332a89d9f6583c1dd879561e9 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 18:31:19 +0800 Subject: [PATCH 36/49] fix(acp): stream append-only answer text, not the re-rendered tool display (F2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACP streamed `compose_display(tool_lines, text)` snapshots over `edit_message`, but the tool-status prefix (🔧/✅ …) is re-rendered as tools progress, so the snapshot is a non-append REPLACEMENT — while `agent_message_chunk` is append-only and acp_server's stream_delta assumes append. The mismatch duplicated/garbled/truncated tool-involving replies (e.g. "…資訊。打資訊。"). For the `acp` platform, stream the raw append-only answer text instead of the tool-merged display (new `display_for` helper; `platform_is_acp` gates the four reply-path call sites). Tool activity will be surfaced separately as structured `tool_call` session/update notifications (roadmap, ADR §6). Other platforms are unchanged. Addresses review finding F2 (streaming completion / replacement). Co-Authored-By: Claude Opus 4.8 --- crates/openab-core/src/adapter.rs | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/crates/openab-core/src/adapter.rs b/crates/openab-core/src/adapter.rs index 88ec72b18..e56784682 100644 --- a/crates/openab-core/src/adapter.rs +++ b/crates/openab-core/src/adapter.rs @@ -720,6 +720,10 @@ impl AdapterRouter { self.table_mode }; let tool_display = self.reactions_config.tool_display; + // ACP streams over an append-only `agent_message_chunk`; a re-rendered tool-status + // prefix from `compose_display` would corrupt the deltas, so ACP streams the raw + // append-only answer text and surfaces tools separately (review F2 / roadmap). + let platform_is_acp = thread_channel.platform == "acp"; let prompt_hard_timeout = self.prompt_hard_timeout; let liveness_check_interval = self.liveness_check_interval; @@ -947,7 +951,8 @@ impl AdapterRouter { } } } else if let Some(tx) = &buf_tx { - let _ = tx.send(compose_display( + let _ = tx.send(display_for( + platform_is_acp, &tool_lines, &text_buf, true, @@ -996,7 +1001,8 @@ impl AdapterRouter { } // Post+edit live update (no-op under native streaming: buf_tx is None). if let Some(tx) = &buf_tx { - let _ = tx.send(compose_display( + let _ = tx.send(display_for( + platform_is_acp, &tool_lines, &text_buf, true, @@ -1041,7 +1047,8 @@ impl AdapterRouter { }); } if let Some(tx) = &buf_tx { - let _ = tx.send(compose_display( + let _ = tx.send(display_for( + platform_is_acp, &tool_lines, &text_buf, true, @@ -1100,7 +1107,7 @@ impl AdapterRouter { // Build final content let final_content = - compose_display(&tool_lines, &text_buf, false, tool_display); + display_for(platform_is_acp, &tool_lines, &text_buf, false, tool_display); let final_content = if final_content.is_empty() { if turn_result.is_silent_failure() { warn!( @@ -1488,6 +1495,25 @@ pub(crate) fn classify_empty_turn( } } +/// Content to stream/deliver for a reply. ACP gets the raw append-only answer `text` +/// (its `agent_message_chunk` stream is append-only, so a re-rendered `compose_display` +/// tool-status prefix would corrupt the deltas — review F2); tool activity is surfaced +/// separately as structured `tool_call` updates (roadmap). Every other platform gets the +/// tool-merged display. +fn display_for( + platform_is_acp: bool, + tool_lines: &[ToolEntry], + text: &str, + streaming: bool, + tool_display: ToolDisplay, +) -> String { + if platform_is_acp { + text.to_string() + } else { + compose_display(tool_lines, text, streaming, tool_display) + } +} + fn compose_display( tool_lines: &[ToolEntry], text: &str, From c51b0f647488c8a6919810f32cd1690ea2982c82 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 18:44:19 +0800 Subject: [PATCH 37/49] test(acp): add lifecycle e2e checks (cancel, oversized-frame close, header auth) New "Lifecycle / transport" group in the conformance suite: session/cancel ends the in-flight prompt with stopReason:"cancelled" (the base cancel primitive's effect, not just its notification silence); an oversized frame closes the connection (F7); and a valid token is accepted via the Authorization: Bearer header (the non-browser transport path). Verified 27/27 against a live deployment. Co-Authored-By: Claude Opus 4.8 --- scripts/acp-ws-smoke.py | 54 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py index b38053080..d2743769c 100755 --- a/scripts/acp-ws-smoke.py +++ b/scripts/acp-ws-smoke.py @@ -255,6 +255,57 @@ async def section_edges(): "CJK + emoji (ZWJ family) stream intact", repr(text[:40])) +async def section_lifecycle(): + print("\n[Lifecycle / transport] — cancel, oversized frame, header auth", flush=True) + from websockets.exceptions import ConnectionClosed + + # valid token via the Authorization: Bearer header (non-browser path) + try: + ws = await websockets.connect( + BASE_URL, additional_headers={"Authorization": f"Bearer {TOKEN}"}, open_timeout=8 + ) + await ws.close() + record("life", True, "valid token via Authorization: Bearer header accepted") + except Exception as e: # noqa: BLE001 + record("life", False, "valid token via Authorization: Bearer header accepted", repr(e)) + + # oversized frame → the server closes the connection (no fabricated JSON-RPC response) + async with await try_connect(TOKEN) as ws: + await ws.send("x" * ((1 << 20) + 64)) # > MAX_FRAME_BYTES (1 MiB) + try: + await asyncio.wait_for(ws.recv(), timeout=8) + record("life", False, "oversized frame closes the connection", "got a frame back") + except ConnectionClosed: + record("life", True, "oversized frame closes the connection") + except asyncio.TimeoutError: + record("life", False, "oversized frame closes the connection", "no close within 8s") + + # session/cancel → the in-flight prompt ends with stopReason:"cancelled" + async with await try_connect(TOKEN) as ws: + c = Conn(ws) + await c.initialize() + sid = await c.new_session() + c._id += 1 + rid = c._id + await ws.send(json.dumps({"jsonrpc": "2.0", "id": rid, "method": "session/prompt", + "params": {"sessionId": sid, "prompt": [{"type": "text", + "text": "Count from 1 to 400, one number per line, slowly."}]}})) + # wait for streaming to start, then cancel (a notification: no id) + started = False + while not started: + m = json.loads(await asyncio.wait_for(ws.recv(), timeout=30)) + if m.get("method") == "session/update": + started = True + await ws.send(json.dumps({"jsonrpc": "2.0", "method": "session/cancel", "params": {"sessionId": sid}})) + stop = None + while True: + m = json.loads(await asyncio.wait_for(ws.recv(), timeout=60)) + if m.get("id") == rid: + stop = m.get("result", {}).get("stopReason") + break + record("life", stop == "cancelled", "session/cancel → prompt ends stopReason:cancelled", f"got {stop!r}") + + async def main() -> int: if not TOKEN: print("ERROR: OPENAB_ACP_TOKEN is required (the /acp endpoint mandates a transport token off loopback).", file=sys.stderr) @@ -263,6 +314,7 @@ async def main() -> int: await section_auth() await section_compliance() await section_edges() + await section_lifecycle() total = len(results) passed = sum(1 for _, ok, _ in results if ok) @@ -273,7 +325,7 @@ async def main() -> int: if ok: s[0] += 1 print("\n" + "-" * 60, flush=True) - labels = {"auth": "Transport / Auth", "comp": "Protocol compliance", "edge": "Protocol edge cases"} + labels = {"auth": "Transport / Auth", "comp": "Protocol compliance", "edge": "Protocol edge cases", "life": "Lifecycle / transport"} for sec, (p, t) in by_section.items(): print(f" {labels.get(sec, sec):22} {p}/{t}", flush=True) print(f"\nRESULT: {passed}/{total} checks passed", flush=True) From f4cca5e46a68876077882e12a4f36232afc4598d Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Sun, 19 Jul 2026 22:28:44 +0800 Subject: [PATCH 38/49] fix(acp): enforce resume session cap, fence stale replies, decouple streaming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group-review follow-ups on the ACP server base: - session/resume now applies the same MAX_SESSIONS_PER_CONNECTION cap as session/new (was an unbounded insert path — a client can mint unlimited sess_); over-cap resume returns -32000. - Fence stale replies after timeout/cancel: register each turn's reply sink under the originating GatewayEvent id (round-tripped as reply_to) so a late reply from a superseded turn is dropped, not delivered into the next prompt's stream on the reused channel_id. - ACP no longer inherits the unified adapter's Telegram streaming flag; it decides streaming explicitly by platform. - has_unified_platform recognises an ACP-only deploy so `openab run` mounts /acp without another platform configured. - Warn when OPENAB_ACP_AUTH_KEY has non-RFC6455-token chars (base64 = and / break the browser subprotocol handshake). - Document the caps/fence/backend-cancel residual in the base ADR. Adds regression tests for the resume cap, the stale-reply fence, and the subprotocol charset check. Co-Authored-By: Claude Opus 4.8 --- crates/openab-core/src/adapter.rs | 10 +- .../openab-gateway/src/adapters/acp_server.rs | 183 ++++++++++++++++-- docs/adr/acp-server-websocket-base.md | 20 ++ src/main.rs | 7 + 4 files changed, 202 insertions(+), 18 deletions(-) diff --git a/crates/openab-core/src/adapter.rs b/crates/openab-core/src/adapter.rs index e56784682..fa7e95dba 100644 --- a/crates/openab-core/src/adapter.rs +++ b/crates/openab-core/src/adapter.rs @@ -701,7 +701,15 @@ impl AdapterRouter { let adapter = adapter.clone(); let thread_channel = thread_channel.clone(); let message_limit = reply_message_limit(&thread_channel.platform, adapter.message_limit()); - let streaming = adapter.use_streaming(other_bot_present); + // ACP must not inherit the unified adapter's Telegram streaming flag (wrong + // coupling): it streams append-only `agent_message_chunk` deltas built from the + // post+edit (`edit_message` snapshot) path, i.e. streaming=false. Decide it + // explicitly by platform rather than by whatever Telegram happens to be set to. + let streaming = if thread_channel.platform == "acp" { + false + } else { + adapter.use_streaming(other_bot_present) + }; // Keep the full turn text (incl. inter-tool narration) when streaming // (it was already shown live) OR when `[reactions] narration_display` is // set. Otherwise a send-once turn delivers only the final answer block. diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index fe4a6ed94..323198581 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -63,6 +63,13 @@ fn subprotocol_token(headers: &axum::http::HeaderMap) -> Option<&str> { }) } +/// RFC 6455 subprotocol values must be RFC 7230 `token`s. `tchar` = ALPHA / DIGIT / +/// `!#$%&'*+-.^_`|~`. A key with any char outside this set (e.g. base64 `/` or `=`) +/// cannot ride the `openab.bearer.` subprotocol on a strict browser handshake. +fn is_ws_subprotocol_token_char(b: u8) -> bool { + b.is_ascii_alphanumeric() || b"!#$%&'*+-.^_`|~".contains(&b) +} + // --------------------------------------------------------------------------- // ACP Configuration // --------------------------------------------------------------------------- @@ -83,11 +90,19 @@ impl AcpConfig { let auth_key = std::env::var("OPENAB_ACP_AUTH_KEY") .ok() .filter(|k| !k.is_empty()); - if auth_key.is_none() { - warn!( + match auth_key { + None => warn!( "OPENAB_ACP_AUTH_KEY not set — /acp is only served on a loopback bind; a \ non-loopback bind will refuse to mount it (set a key to expose it)" - ); + ), + Some(ref key) if !key.bytes().all(is_ws_subprotocol_token_char) => warn!( + "OPENAB_ACP_AUTH_KEY contains characters outside the WebSocket subprotocol \ + token set (RFC 6455) — a browser passing it via `Sec-WebSocket-Protocol: \ + openab.bearer.` may fail the handshake (base64 `/` and `=` padding \ + are the usual offenders). Prefer a key in [A-Za-z0-9._~+-]; the \ + `Authorization: Bearer` and `?token=` paths are unaffected" + ), + Some(_) => {} } Some(Self { auth_key }) } @@ -204,10 +219,21 @@ pub enum ReplyChunk { Done, } -/// Registry of active ACP sessions: channel_id → reply sender. +/// One active turn's reply sink plus the originating `GatewayEvent` id used to fence +/// stale replies. After a prompt times out / is cancelled, the next prompt on the same +/// session reuses the same deterministic `channel_id`; a late reply from the superseded +/// turn carries that turn's `evt_` in `GatewayReply.reply_to`, so matching it +/// against `turn_id` drops it instead of mis-delivering into the new prompt's stream. +pub struct ReplySink { + /// Originating `GatewayEvent.event_id` (`evt_`), round-tripped as `reply_to`. + pub turn_id: String, + pub tx: mpsc::UnboundedSender, +} + +/// Registry of active ACP sessions: channel_id → reply sink. /// Uses std::sync::Mutex because all operations are fast CPU-bound /// (insert/remove/get) and never hold the lock across .await. -pub type AcpReplyRegistry = Arc>>>; +pub type AcpReplyRegistry = Arc>>; pub fn new_reply_registry() -> AcpReplyRegistry { Arc::new(std::sync::Mutex::new(HashMap::new())) @@ -723,7 +749,18 @@ async fn handle_session_resume( } }; - sessions.lock().await.insert( + let mut guard = sessions.lock().await; + // Same per-connection cap as session/new: resume must not be an unbounded insert + // path (a client can mint unlimited valid `sess_`). An already-present key is + // exempt so re-resuming an existing session stays idempotent. + if !guard.contains_key(&session_id) && guard.len() >= MAX_SESSIONS_PER_CONNECTION { + return JsonRpcResponse::error( + id, + ACP_OVERLOADED, + format!("Too many sessions on this connection (max {MAX_SESSIONS_PER_CONNECTION})"), + ); + } + guard.insert( session_id.clone(), AcpSession { channel_id, @@ -731,6 +768,7 @@ async fn handle_session_resume( cancel: None, }, ); + drop(guard); debug!(session = %session_id, "ACP session resumed"); @@ -800,16 +838,8 @@ async fn handle_session_prompt( } }; - // Create reply channel for this prompt and register it - let (reply_tx, mut reply_rx) = mpsc::unbounded_channel::(); - if let Some(ref registry) = state.acp_reply_registry { - registry - .lock() - .unwrap_or_else(|e| e.into_inner()) - .insert(channel_id.clone(), reply_tx); - } - - // Convert to GatewayEvent and dispatch + // Convert to GatewayEvent and dispatch. Build it first so its `event_id` can fence + // this turn's replies (round-tripped as `GatewayReply.reply_to`). let event = GatewayEvent::new( "acp", ChannelInfo { @@ -827,6 +857,17 @@ async fn handle_session_prompt( &format!("acpmsg_{}", Uuid::new_v4()), Vec::new(), ); + let turn_id = event.event_id.clone(); + + // Create reply channel for this prompt and register it, keyed by channel_id with the + // turn's event id so `handle_reply` can drop a stale reply after timeout/cancel reuse. + let (reply_tx, mut reply_rx) = mpsc::unbounded_channel::(); + if let Some(ref registry) = state.acp_reply_registry { + registry + .lock() + .unwrap_or_else(|e| e.into_inner()) + .insert(channel_id.clone(), ReplySink { turn_id, tx: reply_tx }); + } // Send event through the broadcast channel match serde_json::to_string(&event) { @@ -1018,7 +1059,17 @@ pub async fn handle_reply(reply: &GatewayReply, registry: &AcpReplyRegistry) { let tx = { let map = registry.lock().unwrap_or_else(|e| e.into_inner()); match map.get(key) { - Some(tx) => tx.clone(), + // Fence stale replies: after a timeout/cancel the channel_id is reused by the + // next turn. A late reply carries the previous turn's `evt_` in + // `reply_to`; deliver only when it matches the active turn. Empty `reply_to` + // (no origin id) fails open so legit traffic is never dropped. + Some(sink) if reply.reply_to.is_empty() || reply.reply_to == sink.turn_id => { + sink.tx.clone() + } + Some(_) => { + debug!(channel = key, "ACP dropping stale reply from a superseded turn"); + return; + } None => return, } }; @@ -1468,3 +1519,101 @@ mod acp_handlers { assert_eq!(v["error"]["code"], json!(-32602)); } } + +// --------------------------------------------------------------------------- +// Group-review fixes (M1 resume cap / M2 stale-reply fence / subprotocol charset). +// --------------------------------------------------------------------------- +#[cfg(test)] +mod acp_review_fixes { + use super::*; + use serde_json::json; + use std::collections::HashMap; + use std::sync::Arc; + use uuid::Uuid; + + fn sessions_map() -> Arc>> { + Arc::new(tokio::sync::Mutex::new(HashMap::new())) + } + + // M1 — session/resume enforces the same per-connection cap as session/new, so a + // client cannot grow the map without bound by resuming arbitrary `sess_`. + #[tokio::test] + async fn resume_enforces_session_cap() { + let sessions = sessions_map(); + let mut ids = Vec::new(); + for _ in 0..MAX_SESSIONS_PER_CONNECTION { + let sid = format!("sess_{}", Uuid::new_v4()); + let p = json!({ "sessionId": sid }); + let v = serde_json::to_value(handle_session_resume(&sessions, json!(1), Some(&p)).await) + .unwrap(); + assert_eq!(v["result"], json!({}), "resume under cap should succeed"); + ids.push(sid); + } + assert_eq!(sessions.lock().await.len(), MAX_SESSIONS_PER_CONNECTION); + // A new distinct session over the cap is refused with ACP_OVERLOADED. + let over = json!({ "sessionId": format!("sess_{}", Uuid::new_v4()) }); + let v = serde_json::to_value(handle_session_resume(&sessions, json!(2), Some(&over)).await) + .unwrap(); + assert_eq!(v["error"]["code"], json!(ACP_OVERLOADED), "over-cap resume must be refused"); + // Re-resuming an already-present session is exempt (idempotent). + let existing = json!({ "sessionId": ids[0] }); + let v = + serde_json::to_value(handle_session_resume(&sessions, json!(3), Some(&existing)).await) + .unwrap(); + assert_eq!(v["result"], json!({}), "re-resume of existing session must bypass the cap"); + } + + fn reply(channel_id: &str, reply_to: &str, text: &str, command: Option<&str>) -> GatewayReply { + GatewayReply { + schema: "openab.gateway.reply.v1".into(), + reply_to: reply_to.into(), + platform: "acp".into(), + channel: crate::schema::ReplyChannel { id: channel_id.into(), thread_id: None }, + content: crate::schema::Content { + content_type: "text".into(), + text: text.into(), + attachments: Vec::new(), + }, + command: command.map(|c| c.into()), + request_id: None, + quote_message_id: None, + } + } + + // M2 — a late reply carrying a superseded turn's event id is dropped, not delivered + // into the current turn's stream; a reply matching the active turn is delivered. + #[tokio::test] + async fn handle_reply_fences_stale_turn() { + let registry = new_reply_registry(); + let (tx, mut rx) = mpsc::unbounded_channel::(); + registry + .lock() + .unwrap() + .insert("acp_chan".into(), ReplySink { turn_id: "evt_current".into(), tx }); + + // Stale reply (previous turn's event id) → dropped. + handle_reply(&reply("acp_chan", "evt_stale", "leaked", Some("edit_message")), ®istry) + .await; + assert!(rx.try_recv().is_err(), "stale reply must not reach the active turn"); + + // Matching reply → delivered. + handle_reply(&reply("acp_chan", "evt_current", "hello", Some("edit_message")), ®istry) + .await; + match rx.try_recv() { + Ok(ReplyChunk::Text(t)) => assert_eq!(t, "hello"), + _ => panic!("expected the matching reply to be delivered"), + } + } + + // subprotocol charset (n1) — base64 `/` and `=` are not RFC 6455 token chars; the + // recommended `[A-Za-z0-9._~+-]` set (plus other tchars) is. + #[test] + fn ws_subprotocol_token_charset() { + for &b in b"AZaz09._~+-!#$%&'*^`|" { + assert!(is_ws_subprotocol_token_char(b), "{} should be token-safe", b as char); + } + for &b in b"=/,; @\"" { + assert!(!is_ws_subprotocol_token_char(b), "{} should be rejected", b as char); + } + } +} diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 535e428c8..4dc281212 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -102,6 +102,26 @@ all `false` in the base (text only). `protocolVersion` is the integer `1`. `cancelled`. A backend timeout has no ACP stopReason, so it returns a JSON-RPC error (`-32603`) instead. +### Concurrency, caps & reply fencing + +- **Per-connection caps** — `MAX_SESSIONS_PER_CONNECTION` (128) and + `MAX_INFLIGHT_PROMPTS` (32) bound one connection's growth; overflow returns `-32000` + (`ACP_OVERLOADED`). The session cap is enforced on **both** `session/new` and + `session/resume` — resume is not an unbounded insert path (a client can mint unlimited + well-formed `sess_`). +- **Stale-reply fencing** — after a prompt times out or is cancelled, the next prompt on + the same session reuses the same deterministic `channel_id`. Each turn registers its + reply sink under the originating `GatewayEvent` id (`evt_`, round-tripped as + `GatewayReply.reply_to`); `handle_reply` drops a reply whose `reply_to` no longer + matches the active turn, so a late reply from the superseded turn cannot leak into the + new prompt's stream. +- **Backend work is not yet cancelled** — the inflight cap counts *gateway* stream tasks, + not downstream agent work. A timed-out / cancelled turn keeps running on the backend + until it finishes on its own; a `prompt → cancel` loop can therefore queue backend work + beyond the 32 cap. Bounding this needs true agent→core cancel propagation — tracked as a + follow-up, not addressed in the base (the fence above still prevents its late output from + corrupting a later turn). + ### Session ↔ core mapping - `sessionId = sess_` and `channel_id = acp_` share one uuid, so diff --git a/src/main.rs b/src/main.rs index 2a014979d..8d7035ca4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -137,6 +137,13 @@ fn has_unified_platform(cfg: &config::Config) -> bool { .unwrap_or_default() .resolve() .enabled) + // ACP is a first-class embedded endpoint: an ACP-only deploy (no discord/slack/ + // gateway/telegram) must not trip the "no adapter configured" preflight bail and + // must start the embedded HTTP server that hosts /acp. + || (cfg!(feature = "acp") + && std::env::var("OPENAB_ACP_ENABLED") + .map(|v| v == "true" || v == "1") + .unwrap_or(false)) } /// Returns true when the first-class `[wecom]` section resolves all credentials From acb0bde66f680c6877b49c6dbab690c630916a2a Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Wed, 22 Jul 2026 03:32:21 +0800 Subject: [PATCH 39/49] fix(smoke): require every emoji/CJK marker + fail-closed on error (R16-F5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ZWJ-family check parsed as `("🎉" in text and "👨‍👩‍👧‍👦" in text) or ("👨" in text)`, so a lone 👨 (or any partial reply) passed. Require ALL of 你好/🎉/👨‍👩‍👧‍👦/❤️ via all(), and fail closed first on a timeout or JSON-RPC error so a dropped reply can't slip through the content assertion. Script-only. Co-Authored-By: Claude Opus 4.8 --- scripts/acp-ws-smoke.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/acp-ws-smoke.py b/scripts/acp-ws-smoke.py index d2743769c..cfc313edd 100755 --- a/scripts/acp-ws-smoke.py +++ b/scripts/acp-ws-smoke.py @@ -251,8 +251,16 @@ async def section_edges(): r = await c.call("session/prompt", {"sessionId": sid, "prompt": [{"type": "text", "text": "Reply with exactly this and nothing else: 你好 🎉 👨‍👩‍👧‍👦 ❤️"}]}, timeout=90) text = "".join(r.get("chunks", [])) - record("edge", "🎉" in text and "👨‍👩‍👧‍👦" in text or "👨" in text, - "CJK + emoji (ZWJ family) stream intact", repr(text[:40])) + # Require EVERY marker (the old `a and b or c` parsed as `(a and b) or c`, so a lone 👨 + # passed). Fail closed first on a timeout / JSON-RPC error so a dropped reply can't slip + # through the content check. + markers = ["你好", "🎉", "👨‍👩‍👧‍👦", "❤️"] + ok = ( + not r.get("_timeout") + and not r.get("error") + and all(m in text for m in markers) + ) + record("edge", ok, "CJK + emoji (ZWJ family) stream intact", repr(text[:40])) async def section_lifecycle(): From 70847fe1890599ee0c2aeacfb99f7761ac9773d7 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Wed, 22 Jul 2026 04:23:29 +0800 Subject: [PATCH 40/49] ci: run acp-gated gateway tests + unified build (R16-F4) `cargo test --workspace` builds with default features, so openab-gateway's `acp`-gated conformance/handler/streaming tests never compiled or ran in CI (and the old comment claiming they were "covered by cargo test --workspace" was wrong). Add an explicit `cargo test -p openab-gateway --features acp` step (scoped to the one crate to avoid the workspace hooks::tests parallel flake) and a `cargo build --features unified` step so the embedded /acp endpoint is compiled in CI. YAML validated with yq; local unified gate green (clippy + full test + build). Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53b5ea6f9..b7ec296af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,9 +50,14 @@ jobs: run: cargo clippy --workspace --features unified -- -D warnings - name: cargo test run: cargo test --workspace - - # gateway tests are now covered by `cargo test --workspace` in the check job above - # (openab-gateway is a workspace member in crates/openab-gateway/) + # `cargo test --workspace` builds with default features, so openab-gateway's `acp`-gated + # conformance/handler/streaming tests never compile or run. Exercise them explicitly, and + # build the unified binary so the embedded /acp endpoint is compiled in CI. Scoped to + # `-p openab-gateway` to avoid the workspace hooks::tests parallel flake. + - name: cargo test (acp gateway) + run: cargo test -p openab-gateway --features acp + - name: cargo build (unified) + run: cargo build --features unified operator: needs: changes From eb3cf07f088fa4e1f128fed36474650c7f4b6d5a Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Wed, 22 Jul 2026 04:48:26 +0800 Subject: [PATCH 41/49] =?UTF-8?q?fix(acp):=20reserve=20prompt=20cancel=20s?= =?UTF-8?q?tate=20before=20spawn=20=E2=80=94=20fix=20prompt=E2=86=92cancel?= =?UTF-8?q?=20race=20(R16-F1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An immediate session/prompt → session/cancel could process the cancel before the spawned prompt task installed its cancel handle: s.cancel was still None, so the notification was dropped and the prompt ran uncancelled. Move the reservation (busy-check + install the cancel Notify, under the session lock) into the session/prompt read-loop branch, synchronously, BEFORE tokio::spawn — the read loop is sequential, so a cancel on the next frame now finds s.cancel installed. The handler takes the reserved session_id + cancel, releases the reservation on every early return (new release_prompt helper), and no longer re-reserves. A tokio::Notify stores one permit, so even a cancel fired before the handler's select! is consumed as stopReason "cancelled". Regression test: pre-reserved session + pre-fired cancel → the turn resolves "cancelled" and the reservation is released. Gate: clippy --features unified -D warnings + test --features unified (705+292) + build, all green. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 177 +++++++++++++----- 1 file changed, 135 insertions(+), 42 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 323198581..192db1852 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -547,6 +547,56 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); continue; } + // Reserve this prompt's cancel state SYNCHRONOUSLY here — before spawning the + // async handler — so a `session/cancel` arriving on the very next frame finds + // `s.cancel` already installed. The read loop is sequential; installing the cancel + // inside the spawned task (as it was) left a window where an immediate cancel read + // `s.cancel == None` and was dropped, so the prompt ran uncancelled (R16-F1). + // Unknown-session / busy are rejected here (moved out of the handler). + let session_id = match req + .params + .as_ref() + .and_then(|p| p.get("sessionId")) + .and_then(|v| v.as_str()) + { + Some(s) => s.to_string(), + None => { + let resp = JsonRpcResponse::error(id, -32602, "Missing sessionId"); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + }; + let cancel = Arc::new(tokio::sync::Notify::new()); + { + let mut guard = sessions.lock().await; + match guard.get_mut(&session_id) { + None => { + drop(guard); + let resp = JsonRpcResponse::error( + id, + -32602, + format!("Unknown session: {session_id}"), + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + Some(s) if s.busy => { + drop(guard); + let resp = JsonRpcResponse::error( + id, + -32001, + "Session busy: a prompt is already in progress", + ); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + continue; + } + Some(s) => { + s.busy = true; + s.cancel = Some(cancel.clone()); + } + } + } + // session/prompt is async — spawn a task to handle streaming let state_clone = state.clone(); let sessions_clone = sessions.clone(); @@ -558,6 +608,8 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { id, req.params.as_ref(), &out_tx_clone, + session_id, + cancel, ) .await; }); @@ -786,55 +838,49 @@ fn derive_channel_id(session_id: &str) -> Option { Some(format!("acp_{uuid}")) } +/// Release a prompt reservation: clear `busy` and drop the cancel handle. Called on every +/// early return once the read loop has reserved the session (R16-F1). +async fn release_prompt( + sessions: &Arc>>, + session_id: &str, +) { + if let Some(s) = sessions.lock().await.get_mut(session_id) { + s.busy = false; + s.cancel = None; + } +} + async fn handle_session_prompt( state: &Arc, sessions: &Arc>>, id: Value, params: Option<&Value>, out_tx: &mpsc::UnboundedSender, + // The caller (read loop) already reserved this session SYNCHRONOUSLY: `busy = true` and + // `cancel` installed under the session lock (R16-F1). This task owns releasing it on return. + session_id: String, + cancel: Arc, ) { - // Extract sessionId and prompt from params - let (session_id, prompt_text) = match extract_prompt_params(params) { - Ok(v) => v, + // sessionId was validated + reserved by the caller; only the prompt body can still be bad. + let prompt_text = match extract_prompt_params(params) { + Ok((_sid, text)) => text, Err(e) => { let resp = JsonRpcResponse::error(id, -32602, e); let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + release_prompt(sessions, &session_id).await; return; } }; - // Cancel signal for this prompt; `session/cancel` fires it to stop the - // stream gracefully. - let cancel = Arc::new(tokio::sync::Notify::new()); - - // Look up session and acquire busy lock - let channel_id = { - let mut guard = sessions.lock().await; - match guard.get_mut(&session_id) { - Some(s) => { - if s.busy { - // Reject concurrent prompts on the same session - let resp = JsonRpcResponse::error( - id, - -32001, - "Session busy: a prompt is already in progress", - ); - let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); - return; - } - s.busy = true; - s.cancel = Some(cancel.clone()); - s.channel_id.clone() - } - None => { - let resp = JsonRpcResponse::error( - id, - -32602, - format!("Unknown session: {session_id}"), - ); - let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); - return; - } + // The session was reserved a moment ago under the lock; just read its channel_id. + let channel_id = match sessions.lock().await.get(&session_id) { + Some(s) => s.channel_id.clone(), + None => { + let resp = + JsonRpcResponse::error(id, -32602, format!("Unknown session: {session_id}")); + let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); + release_prompt(sessions, &session_id).await; + return; } }; @@ -881,10 +927,7 @@ async fn handle_session_prompt( "No agent backend connected", ); let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); - // Release busy flag - if let Some(s) = sessions.lock().await.get_mut(&session_id) { - s.busy = false; - } + release_prompt(sessions, &session_id).await; // Cleanup registry if let Some(ref registry) = state.acp_reply_registry { registry.lock().unwrap_or_else(|e| e.into_inner()).remove(&channel_id); @@ -896,9 +939,7 @@ async fn handle_session_prompt( warn!("ACP: failed to serialize event: {e}"); let resp = JsonRpcResponse::error(id, -32603, "Internal error"); let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); - if let Some(s) = sessions.lock().await.get_mut(&session_id) { - s.busy = false; - } + release_prompt(sessions, &session_id).await; return; } } @@ -1616,4 +1657,56 @@ mod acp_review_fixes { assert!(!is_ws_subprotocol_token_char(b), "{} should be rejected", b as char); } } + + // R16-F1 — the read loop now reserves the prompt's cancel state SYNCHRONOUSLY (busy + a + // cancel Notify installed under the session lock) before spawning the handler. So a + // `session/cancel` arriving before the handler reaches its stream `select!` still cancels + // the turn: `tokio::Notify` stores one permit, so a pre-fired cancel is consumed by + // `cancel.notified()` (stopReason "cancelled") rather than lost. Before the fix the cancel + // installed inside the spawned task, so an immediate cancel read `s.cancel == None`. + #[tokio::test] + async fn prompt_cancel_race_before_first_update_cancels() { + let (event_tx, _event_rx) = tokio::sync::broadcast::channel::(16); + let mut st = crate::AppState::test_default(event_tx); + st.acp_reply_registry = Some(new_reply_registry()); + let state = Arc::new(st); + + let sessions = sessions_map(); + let sid = format!("sess_{}", Uuid::new_v4()); + let cancel = Arc::new(tokio::sync::Notify::new()); + sessions.lock().await.insert( + sid.clone(), + AcpSession { + channel_id: format!("acp_{}", Uuid::new_v4()), + busy: true, + cancel: Some(cancel.clone()), + }, + ); + // Cancel arrives before the handler's stream loop (reserved-then-immediate-cancel). + cancel.notify_one(); + + let (out_tx, mut out_rx) = mpsc::unbounded_channel::(); + let params = json!({"sessionId": sid, "prompt": [{"type": "text", "text": "hi"}]}); + handle_session_prompt(&state, &sessions, json!(7), Some(¶ms), &out_tx, sid.clone(), cancel) + .await; + + // The final response (matching our request id) must carry stopReason "cancelled". + let mut final_resp = None; + while let Ok(s) = out_rx.try_recv() { + let v: serde_json::Value = serde_json::from_str(&s).unwrap(); + if v.get("id") == Some(&json!(7)) { + final_resp = Some(v); + } + } + let resp = final_resp.expect("prompt must produce a final response"); + assert_eq!( + resp["result"]["stopReason"], + json!("cancelled"), + "an immediate cancel must cancel the turn, not be dropped" + ); + // And the reservation is released. + let g = sessions.lock().await; + let s = g.get(&sid).unwrap(); + assert!(!s.busy && s.cancel.is_none(), "cancel must release busy + cancel handle"); + } } From 1388591d708cc01ce3bccd8766320cda0f1b0c90 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Wed, 22 Jul 2026 05:09:17 +0800 Subject: [PATCH 42/49] fix(acp): reject session/resume while a prompt is in flight (R16-F2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handle_session_resume unconditionally rewrote AcpSession{busy:false,cancel:None}. Resuming during an active prompt therefore dropped the in-flight turn's cancel handle, and then that turn's cleanup clobbered the freshly-resumed registry entry / state — losing the newer turn's replies. Minimal, deterministic fix: reject a resume whose local session is currently `busy` with a JSON-RPC -32001, leaving the active turn's busy flag + cancel handle untouched (owner/generation tagging is the Phase-2 robust variant, deferred). Regression test: resume against a busy session is rejected and the session's busy + cancel survive. Gate: clippy --features unified -D warnings + test --features unified (705+293) + build, green. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 192db1852..cc6e00e09 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -812,6 +812,18 @@ async fn handle_session_resume( format!("Too many sessions on this connection (max {MAX_SESSIONS_PER_CONNECTION})"), ); } + // R16-F2: refuse to resume a session that currently has a prompt in flight. The insert + // below unconditionally rewrites AcpSession{busy:false,cancel:None}, which would drop the + // active turn's cancel handle — and then that turn's cleanup would clobber the resumed + // state / registry entry, losing its replies. A busy session is already live on this + // connection, so reject deterministically instead of stomping it. + if guard.get(&session_id).is_some_and(|s| s.busy) { + return JsonRpcResponse::error( + id, + -32001, + "Session busy: a prompt is in progress; cannot resume", + ); + } guard.insert( session_id.clone(), AcpSession { @@ -1709,4 +1721,33 @@ mod acp_review_fixes { let s = g.get(&sid).unwrap(); assert!(!s.busy && s.cancel.is_none(), "cancel must release busy + cancel handle"); } + + // R16-F2 — session/resume on a session with a prompt in flight is rejected (busy), so the + // active turn's cancel handle + state are NOT clobbered by resume's unconditional rewrite. + #[tokio::test] + async fn resume_while_busy_is_rejected_and_preserves_state() { + let sessions = sessions_map(); + let sid = format!("sess_{}", Uuid::new_v4()); + let cancel = Arc::new(tokio::sync::Notify::new()); + sessions.lock().await.insert( + sid.clone(), + AcpSession { + channel_id: format!("acp_{}", Uuid::new_v4()), + busy: true, + cancel: Some(cancel.clone()), + }, + ); + + let params = json!({"sessionId": sid, "cwd": "/w", "mcpServers": []}); + let v = + serde_json::to_value(handle_session_resume(&sessions, json!(9), Some(¶ms)).await) + .unwrap(); + assert_eq!(v["error"]["code"], json!(-32001), "resume while busy must be rejected"); + + // The in-flight turn's state survives untouched. + let g = sessions.lock().await; + let s = g.get(&sid).unwrap(); + assert!(s.busy, "busy must remain set after a rejected resume"); + assert!(s.cancel.is_some(), "the active prompt's cancel handle must survive resume"); + } } From c314ece6f2b8bce112db06356c0c8aaf4f6913d7 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Wed, 22 Jul 2026 05:29:26 +0800 Subject: [PATCH 43/49] docs(acp): narrow Phase-1 streaming contract to single terminal chunk (R16-F3 option A) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACP ChatAdapter is streaming=false, so Phase-1 delivers the whole reply as one terminal agent_message_chunk before the session/prompt response — not progressive multi-chunk streaming. Align the docs to that reality (option A; progressive streaming stays Phase-2, not implemented here): - ADR acp-server-websocket-base.md: reword the §1 scope + the agent_message_chunk acceptance wording to "single terminal chunk (streaming=false)", and add a Phase-2 progressive-streaming roadmap bullet under §6. - PR #1418 body: softened the At-a-Glance diagram + Proposed-Solution line the same way (wording-only; applied via gh, everything else byte-for-byte). - Test phase1_emits_single_terminal_agent_message_chunk: a final (send_message) reply yields exactly ONE agent_message_chunk + stopReason end_turn, anchoring the claim. Gate: clippy --features unified -D warnings + test --features unified (705+294) + build, green. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 61 +++++++++++++++++++ docs/adr/acp-server-websocket-base.md | 22 +++++-- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index cc6e00e09..5a6bee9de 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -1750,4 +1750,65 @@ mod acp_review_fixes { assert!(s.busy, "busy must remain set after a rejected resume"); assert!(s.cancel.is_some(), "the active prompt's cancel handle must survive resume"); } + + // R16-F3(A) — Phase-1 send-once: the ACP path streams the whole reply as a SINGLE terminal + // agent_message_chunk (backend streaming=false), which anchors the ADR/PR doc claim. A final + // reply (`send_message`) delivers one Text + Done, so exactly one chunk reaches the client. + #[tokio::test] + async fn phase1_emits_single_terminal_agent_message_chunk() { + let (event_tx, _event_rx) = tokio::sync::broadcast::channel::(16); + let registry = new_reply_registry(); + let mut st = crate::AppState::test_default(event_tx); + st.acp_reply_registry = Some(registry.clone()); + let state = Arc::new(st); + + let sessions = sessions_map(); + let sid = format!("sess_{}", Uuid::new_v4()); + let channel_id = format!("acp_{}", Uuid::new_v4()); + let cancel = Arc::new(tokio::sync::Notify::new()); + sessions.lock().await.insert( + sid.clone(), + AcpSession { channel_id: channel_id.clone(), busy: true, cancel: Some(cancel.clone()) }, + ); + + let (out_tx, mut out_rx) = mpsc::unbounded_channel::(); + let st2 = state.clone(); + let sessions2 = sessions.clone(); + let sid2 = sid.clone(); + let handle = tokio::spawn(async move { + let params = json!({"sessionId": sid2, "prompt": [{"type": "text", "text": "hi"}]}); + handle_session_prompt(&st2, &sessions2, json!(11), Some(¶ms), &out_tx, sid2.clone(), cancel) + .await; + }); + + // Wait for the handler to register its reply sink, then feed one final reply. + let mut turn_id = None; + for _ in 0..10_000 { + if let Some(t) = registry.lock().unwrap().get(&channel_id).map(|s| s.turn_id.clone()) { + turn_id = Some(t); + break; + } + tokio::task::yield_now().await; + } + let turn_id = turn_id.expect("handler must register a reply sink"); + handle_reply(&reply(&channel_id, &turn_id, "hello world", Some("send_message")), ®istry).await; + handle.await.unwrap(); + + let mut chunks = Vec::new(); + let mut final_stop = None; + while let Ok(s) = out_rx.try_recv() { + let v: serde_json::Value = serde_json::from_str(&s).unwrap(); + if v["method"] == json!("session/update") + && v["params"]["update"]["sessionUpdate"] == json!("agent_message_chunk") + { + chunks.push(v["params"]["update"]["content"]["text"].as_str().unwrap_or("").to_string()); + } + if v.get("id") == Some(&json!(11)) { + final_stop = v["result"]["stopReason"].as_str().map(str::to_string); + } + } + assert_eq!(chunks.len(), 1, "Phase-1 must stream exactly one terminal chunk, got {chunks:?}"); + assert_eq!(chunks[0], "hello world"); + assert_eq!(final_stop.as_deref(), Some("end_turn"), "a completed turn ends end_turn"); + } } diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 4dc281212..6338da6cc 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -16,9 +16,11 @@ the full ACP-server vision across five phases. This ADR is the **as-built record the base** — the concrete, **wire-conformant** primitive surface the implementation ships and that future work should follow. -Scope: a standard-ACP **1:1 streaming chat** endpoint for real ACP clients (browser, -desktop, IDE, CLI) over WebSocket. Not in the base: tool calls / permissions, client -fs/terminal methods, multi-agent fan-out, Streamable HTTP. +Scope: a standard-ACP **1:1 chat** endpoint for real ACP clients (browser, +desktop, IDE, CLI) over WebSocket. Phase-1 returns each reply as a single terminal +`agent_message_chunk` (backend `streaming=false`); progressive multi-chunk streaming is +Phase-2 (§6). Not in the base: tool calls / permissions, client fs/terminal methods, +multi-agent fan-out, Streamable HTTP. Design goal (per decision on 2026-07-17): **follow the official ACP guide** so third-party ACP clients (Zed, JetBrains, …) interoperate — no custom method names. @@ -94,9 +96,12 @@ all `false` in the base (text only). `protocolVersion` is the integer `1`. ### Agent → Client (notification) - `session/update` with `update.sessionUpdate = "agent_message_chunk"` and - `update.content = { type:"text", text: }` — streamed reply text. Delta is - sliced char-boundary-safe (`str::get`, never byte-index) so CJK / 顏文字 / emoji - cannot panic the stream. + `update.content = { type:"text", text: }` — reply text. **Phase-1 delivers the + whole reply as a single terminal `agent_message_chunk` before the `session/prompt` + response** — the ACP `ChatAdapter` is `streaming=false`, so the backend hands the reply + over once rather than incrementally. Progressive multi-chunk streaming is Phase-2 (§6). + The delta is still sliced char-boundary-safe (`str::get`, never byte-index) so CJK / + 顏文字 / emoji cannot panic the stream if/when multiple chunks arrive. - Turn completion is the `session/prompt` **response** (`{ stopReason }`, correlated to the request id), not a separate notification. `stopReason` ∈ `end_turn` / `cancelled`. A backend timeout has no ACP stopReason, so it returns a JSON-RPC @@ -226,6 +231,11 @@ North star: the agent's LLM autonomously operating the user's real browser (gene `toolCallId` / `title` / `status`) separately from the text — this is the ACP-native path (standard clients like Zed render it too), avoids brittle client-side text parsing, and cleanly separates tool activity from the answer. Client (extension) then renders chips. +- **Progressive `agent_message_chunk` streaming (Phase-2)** — Phase-1 emits the whole reply + as one terminal chunk because the ACP `ChatAdapter` reports `streaming=false`, so the + backend hands the reply over once. True incremental delivery — flip the adapter to + streaming and emit a chunk per delta as the backend produces text — is Phase-2; the + gateway's char-boundary-safe delta path already tolerates multiple chunks. - other richer `session/update` variants: `agent_thought_chunk` / `plan` / `available_commands_update` / `usage_update` - `fs/*`, `terminal/*` (sibling agent→client capabilities) From f7c937837bfb02b248d86ef28ed4fd5dbd8d1a63 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Wed, 22 Jul 2026 09:08:58 +0800 Subject: [PATCH 44/49] docs(acp): note the busy-gate invariant that keeps prompt cleanup safe (R16-F2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unconditional registry remove / busy reset in the prompt cleanup path is correct only because no newer turn can exist on the same session_id while one is in flight — session/prompt and session/resume both reject with -32001 when busy. Document that coupling so a future relaxation of the busy gate doesn't silently reintroduce the F2 cleanup-clobber; cross-connection ownership stays a residual (F5). Co-Authored-By: Claude Opus 4.8 --- crates/openab-gateway/src/adapters/acp_server.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 5a6bee9de..3515ff502 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -1007,6 +1007,12 @@ async fn handle_session_prompt( } // Cleanup: remove from registry, release busy flag, clear cancel signal. + // INVARIANT (R16-F1/F2): this unconditional remove/reset is safe ONLY because no newer + // turn can exist on this `session_id` while this one runs — both entry points that would + // start one are busy-gated (`session/prompt` and `session/resume` reject with -32001 when + // `s.busy`). If that gating is ever relaxed (e.g. multi-turn-per-session), this must become + // turn/owner-aware (compare the active `turn_id` before `remove`) or it will clobber the + // newer turn's sink. Cross-connection same-session races remain an accepted residual (F5). if let Some(ref registry) = state.acp_reply_registry { registry.lock().unwrap_or_else(|e| e.into_inner()).remove(&channel_id); } From 6ee620cfd25140c05bb10ddcd6a6e70ed64043db Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Thu, 23 Jul 2026 15:30:21 +0800 Subject: [PATCH 45/49] fix(acp): validate browser Origin in keyless loopback mode (R17-F1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WS handshakes bypass the browser same-origin policy, so a keyless `ws://127.0.0.1/acp` was reachable cross-origin by any web page. In keyless mode the upgrade handler now rejects a browser-set `Origin` that is not allowlisted (403); a request with no `Origin` (non-browser client) is still admitted, and the keyed/bearer path is unchanged. The allowlist is opt-in via `OPENAB_ACP_ALLOWED_ORIGINS` (comma-separated), plumbed through `AcpConfig` next to `auth_key`. Documented in the ADR §2 security note. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 77 ++++++++++++++++++- docs/adr/acp-server-websocket-base.md | 10 +++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 3515ff502..bc3ffdf52 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -76,6 +76,10 @@ fn is_ws_subprotocol_token_char(b: u8) -> bool { pub struct AcpConfig { pub auth_key: Option, + /// Browser `Origin`s allowed to drive `/acp` in keyless loopback mode (from + /// `OPENAB_ACP_ALLOWED_ORIGINS`, comma-separated). Empty by default → every + /// browser-set `Origin` is rejected; non-browser clients (no `Origin`) are unaffected. + pub allowed_origins: Vec, } impl AcpConfig { @@ -104,7 +108,36 @@ impl AcpConfig { ), Some(_) => {} } - Some(Self { auth_key }) + // Browser-origin allowlist for keyless loopback mode. A WS handshake bypasses the + // browser same-origin policy, so without this any web page could drive a keyless + // `ws://127.0.0.1/acp`. Comma-separated; blanks trimmed. Default empty blocks all + // browser origins (a non-browser client sends no `Origin` and is unaffected). + let allowed_origins = std::env::var("OPENAB_ACP_ALLOWED_ORIGINS") + .ok() + .map(|v| { + v.split(',') + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect::>() + }) + .unwrap_or_default(); + Some(Self { + auth_key, + allowed_origins, + }) + } +} + +/// Whether a **keyless-mode** WS upgrade may proceed given its `Origin` header. WS +/// handshakes are exempt from the browser same-origin policy, so on a keyless loopback +/// bind any web page could otherwise drive `/acp`. A request with no `Origin` (a +/// non-browser client) is allowed; a browser-set `Origin` must be explicitly allowlisted +/// via `OPENAB_ACP_ALLOWED_ORIGINS` (default empty → every browser origin blocked). Keyed +/// binds authenticate via the bearer key and never reach this check. +fn acp_origin_ok(origin: Option<&str>, allowed_origins: &[String]) -> bool { + match origin { + None => true, + Some(o) => allowed_origins.iter().any(|a| a == o), } } @@ -335,6 +368,25 @@ pub async fn ws_upgrade( warn!("ACP WebSocket rejected: invalid or missing token"); return StatusCode::UNAUTHORIZED.into_response(); } + } else { + // Keyless loopback mode: the bearer check above is skipped, so a browser could + // reach us cross-origin (WS handshakes bypass the same-origin policy). Reject a + // browser-set `Origin` that isn't allowlisted; a non-browser client (no `Origin`) + // is allowed. + let origin = headers.get("origin").and_then(|v| v.to_str().ok()); + let allowed = state + .acp + .as_ref() + .map(|c| c.allowed_origins.as_slice()) + .unwrap_or(&[]); + if !acp_origin_ok(origin, allowed) { + warn!( + "ACP WebSocket rejected: browser Origin {:?} not in OPENAB_ACP_ALLOWED_ORIGINS \ + (keyless loopback mode)", + origin + ); + return StatusCode::FORBIDDEN.into_response(); + } } // Echo the `acp.v1` subprotocol so a browser that offered it (alongside its @@ -1664,6 +1716,29 @@ mod acp_review_fixes { } } + // R17-F1 — keyless-mode browser `Origin` gating. A WS handshake bypasses the browser + // same-origin policy, so on a keyless loopback bind an un-allowlisted browser origin + // must be refused (ws_upgrade turns `false` into a 403). A non-browser client sends no + // `Origin` and is always admitted; the keyed path never reaches this check (it lives in + // the `else` of the bearer branch), so a keyed bind is unaffected by the allowlist. + #[test] + fn acp_origin_ok_keyless_gating() { + let allow = vec!["https://app.example".to_string(), "http://localhost:5173".to_string()]; + // Absent Origin (non-browser client) → accept, regardless of allowlist. + assert!(acp_origin_ok(None, &allow), "no Origin (non-browser) must be admitted"); + assert!(acp_origin_ok(None, &[]), "no Origin must be admitted even with empty allowlist"); + // Allowlisted browser Origin → accept (exact match, both entries). + assert!(acp_origin_ok(Some("https://app.example"), &allow)); + assert!(acp_origin_ok(Some("http://localhost:5173"), &allow)); + // Disallowed browser Origin → reject (→ 403 at the handler). + assert!(!acp_origin_ok(Some("https://evil.example"), &allow)); + // Default empty allowlist blocks every browser-set Origin. + assert!(!acp_origin_ok(Some("https://app.example"), &[])); + // Match is exact — no scheme/host/port fuzzing, no trailing-slash leniency. + assert!(!acp_origin_ok(Some("https://app.example/"), &allow)); + assert!(!acp_origin_ok(Some("http://app.example"), &allow)); + } + // subprotocol charset (n1) — base64 `/` and `=` are not RFC 6455 token chars; the // recommended `[A-Za-z0-9._~+-]` set (plus other tchars) is. #[test] diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index 6338da6cc..a1fe3ddab 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -65,6 +65,16 @@ ACP replies are routed back via the unified adapter's `dispatch_reply` (`0.0.0.0`, LAN, LoadBalancer) without a key refuses to mount the endpoint, so an unauthenticated agent endpoint is never exposed to the network. An empty key counts as unset. + + **Browser `Origin` gating in keyless mode:** a WS handshake is exempt from the browser + same-origin policy, so a keyless `ws://127.0.0.1/acp` is otherwise reachable cross-origin + by any web page the user has open. In keyless (loopback) mode the upgrade handler + therefore inspects `Origin`: a browser-set `Origin` that is not allowlisted is rejected + with `403`, while a request with no `Origin` (a non-browser client) is admitted. The + allowlist is opt-in via `OPENAB_ACP_ALLOWED_ORIGINS` (comma-separated exact origins) and + defaults to empty — i.e. every browser origin is blocked until explicitly allowed. The + keyed (bearer) path does not consult `Origin`; the transport key is the trust boundary + there. 2. **Identity** — ACP events carry a fixed synthetic sender id `acp_client` and pass through the gateway trust registry (the `acp` platform is seeded there alongside telegram/line/…). Admit the sender with `GATEWAY_ALLOW_ALL_USERS=true` or From b56ece5b565fc719529bb1fd77738e517d96b997 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Thu, 23 Jul 2026 16:11:42 +0800 Subject: [PATCH 46/49] fix(acp): remove the ?token= query fallback (R17-F2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bearer key in the URL query leaks into access logs / browser history / referers. The two header-borne sources — `Authorization: Bearer` and the `Sec-WebSocket-Protocol: openab.bearer.` subprotocol — already cover both non-browser and browser clients, so drop the legacy `?token=` fallback. Token extraction is factored into `ws_bearer_token` (headers only); the `query`/`Query` extractor is gone from `ws_upgrade`. A request presenting a credential solely via `?token=` is now rejected 401 in keyed mode. ADR §2 updated. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 53 ++++++++++++++----- docs/adr/acp-server-websocket-base.md | 6 ++- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index bc3ffdf52..a757ce2ba 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -14,7 +14,7 @@ use crate::schema::*; use axum::extract::ws::{Message, WebSocket}; -use axum::extract::{Query, State, WebSocketUpgrade}; +use axum::extract::{State, WebSocketUpgrade}; use axum::http::StatusCode; use axum::response::IntoResponse; use futures_util::{SinkExt, StreamExt}; @@ -63,6 +63,21 @@ fn subprotocol_token(headers: &axum::http::HeaderMap) -> Option<&str> { }) } +/// Extract the transport bearer key from a WS upgrade request, in priority order: +/// 1. `Authorization: Bearer ` — non-browser clients (cleanest). +/// 2. `Sec-WebSocket-Protocol: openab.bearer., acp.v1` — browsers (keeps the token +/// out of the URL; the de facto browser-WS bearer pattern). +/// +/// The legacy `?token=` query fallback was removed (R17-F2): it leaks the key into +/// URLs / access logs / history, so only these two header-borne sources carry the bearer. +fn ws_bearer_token(headers: &axum::http::HeaderMap) -> Option<&str> { + headers + .get("authorization") + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.strip_prefix("Bearer ")) + .or_else(|| subprotocol_token(headers)) +} + /// RFC 6455 subprotocol values must be RFC 7230 `token`s. `tchar` = ALPHA / DIGIT / /// `!#$%&'*+-.^_`|~`. A key with any char outside this set (e.g. base64 `/` or `=`) /// cannot ride the `openab.bearer.` subprotocol on a strict browser handshake. @@ -338,21 +353,12 @@ impl JsonRpcResponse { pub async fn ws_upgrade( State(state): State>, - query: Query>, headers: axum::http::HeaderMap, ws: WebSocketUpgrade, ) -> axum::response::Response { - // Bearer token, in priority order: - // 1. `Authorization: Bearer ` — non-browser clients (cleanest). - // 2. `Sec-WebSocket-Protocol: openab.bearer., acp.v1` — browsers (keeps the - // token out of the URL; the de facto browser-WS bearer pattern). - // 3. `?token=` query — legacy fallback; leaks in URLs/logs, deprecated. - let token = headers - .get("authorization") - .and_then(|v| v.to_str().ok()) - .and_then(|v| v.strip_prefix("Bearer ")) - .or_else(|| subprotocol_token(&headers)) - .or_else(|| query.get("token").map(|s| s.as_str())); + // Bearer key from a header-borne source only (Authorization or the WS subprotocol); + // the legacy `?token=` query fallback was dropped in R17-F2. See `ws_bearer_token`. + let token = ws_bearer_token(&headers); let expected = state.acp.as_ref().and_then(|c| c.auth_key.as_ref()); if let Some(expected) = expected { @@ -1739,6 +1745,27 @@ mod acp_review_fixes { assert!(!acp_origin_ok(Some("http://app.example"), &allow)); } + // R17-F2 — the legacy `?token=` query fallback is gone. The bearer is extracted ONLY + // from `Authorization: Bearer` or the `Sec-WebSocket-Protocol` subprotocol; `ws_upgrade` + // no longer reads the query string. A request whose only credential would have been + // `?token=` now carries no header-borne token, so extraction yields None → keyed + // mode rejects it 401 (the query is never consulted). + #[test] + fn ws_bearer_token_ignores_query_only_request() { + use axum::http::HeaderMap; + // No Authorization, no subprotocol → what used to be a `?token=` request now has no + // extractable bearer (None → 401 in keyed mode). + assert_eq!(ws_bearer_token(&HeaderMap::new()), None); + // Authorization: Bearer still carries the key. + let mut h = HeaderMap::new(); + h.insert("authorization", "Bearer sekret".parse().unwrap()); + assert_eq!(ws_bearer_token(&h), Some("sekret")); + // The subprotocol path still carries the key. + let mut h = HeaderMap::new(); + h.insert("sec-websocket-protocol", "openab.bearer.sekret, acp.v1".parse().unwrap()); + assert_eq!(ws_bearer_token(&h), Some("sekret")); + } + // subprotocol charset (n1) — base64 `/` and `=` are not RFC 6455 token chars; the // recommended `[A-Za-z0-9._~+-]` set (plus other tchars) is. #[test] diff --git a/docs/adr/acp-server-websocket-base.md b/docs/adr/acp-server-websocket-base.md index a1fe3ddab..c6f6a2de7 100644 --- a/docs/adr/acp-server-websocket-base.md +++ b/docs/adr/acp-server-websocket-base.md @@ -52,8 +52,10 @@ ACP replies are routed back via the unified adapter's `dispatch_reply` the `openab.bearer.` entry and echoes the real `acp.v1` subprotocol. This is the de facto browser-WS bearer pattern (as used by the Kubernetes API server) and keeps the key **out of the URL**. - 3. **`?token=`** query — legacy fallback only; the key leaks into URLs / access - logs / history, so it is deprecated in favor of the subprotocol. + The `?token=` query fallback was **removed** (R17-F2): a key in the URL leaks into + access logs / browser history / referers, and the two header-borne sources above fully + cover both non-browser and browser clients. Only those two carry the bearer; a request + presenting a credential solely via the query string is rejected `401` in keyed mode. We deliberately do **not** repurpose ACP's `authenticate` / `authMethods` for this: those are agent→provider auth (the client helping a locally-spawned agent log in to its From 077e8e26a743a0153f14ec942151d2ea63208113 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Thu, 23 Jul 2026 16:21:02 +0800 Subject: [PATCH 47/49] fix(acp): reject non-ContentBlock (string) prompt shapes (R17-F3a) The generated `PromptRequest.prompt` is `[ContentBlock]`. `extract_prompt_params` previously coerced a plain-string `prompt` (and fell through to a generic error for other shapes); now any non-array `prompt` is rejected, surfaced as -32602 invalid params at the call site, rather than leniently accepted. Baseline text / resource_link array handling is unchanged. Test updated: a string prompt now returns an error. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index a757ce2ba..8aa35b91f 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -1098,10 +1098,11 @@ fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), Str .to_string(); let prompt = params.get("prompt").ok_or("Missing prompt")?; - // Prompt can be an array of content blocks or a simple string. The base is - // text-only: an unsupported block type (image / audio / resource / resource_link) - // is rejected explicitly rather than silently dropped, so the client knows its - // content was not delivered. + // Per the ACP schema the generated `PromptRequest.prompt` is `[ContentBlock]`; a plain + // string (or any non-array) is non-conformant and rejected below (-32602), never + // leniently coerced. The base is text-only: an unsupported block type (image / audio / + // resource / resource_link) is rejected explicitly rather than silently dropped, so the + // client knows its content was not delivered. let text = if let Some(arr) = prompt.as_array() { let mut parts: Vec = Vec::with_capacity(arr.len()); for block in arr { @@ -1142,10 +1143,10 @@ fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), Str } } parts.join("\n") - } else if let Some(s) = prompt.as_str() { - s.to_string() } else { - return Err("Invalid prompt format".into()); + // A plain-string `prompt` (or any non-array) does not match the generated + // `PromptRequest.prompt: [ContentBlock]` shape → -32602 invalid params. + return Err("Invalid prompt: 'prompt' must be an array of content blocks".into()); }; if text.trim().is_empty() { @@ -1442,9 +1443,18 @@ mod acp_conformance { "prompt": [{"type": "image", "data": "..", "mimeType": "image/png"}] }))) .is_err()); - // a plain-string prompt still works - let (_, s) = extract_prompt_params(Some(&json!({"sessionId": "sess_x", "prompt": "hello"}))).unwrap(); - assert_eq!(s, "hello"); + // R17-F3a — a plain-string prompt is non-conformant (schema requires + // `prompt: [ContentBlock]`) → rejected, surfaced as -32602 at the call site. + assert!( + extract_prompt_params(Some(&json!({"sessionId": "sess_x", "prompt": "hello"}))).is_err(), + "a bare string prompt must be rejected, not coerced" + ); + // an object (non-array, non-string) prompt is likewise rejected. + assert!( + extract_prompt_params(Some(&json!({"sessionId": "sess_x", "prompt": {"type": "text"}}))) + .is_err(), + "a non-array prompt must be rejected" + ); } // --- transport auth gate (F1): no key allowed only on loopback --- From bd726ff86c743f5d11201865a5772fbf0638d2aa Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Thu, 23 Jul 2026 16:40:28 +0800 Subject: [PATCH 48/49] fix(acp): enforce ResourceLink required fields (R17-F3b) The generated `ResourceLink` requires both `name` and `uri`. The prompt parser previously required only `uri`, treating `name` as optional and falling back to `title`/a bare-uri render. It now rejects a resource_link missing its required `name` (-32602 invalid params) rather than silently rendering it, matching the schema. Accepted links still render as `[name](uri)`. Tests updated: a no-`name` link is now an error. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index 8aa35b91f..c42be44d7 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -1118,18 +1118,21 @@ fn extract_prompt_params(params: Option<&Value>) -> Result<(String, String), Str // Baseline ACP content (every agent MUST accept text + resource_link). // We do not fetch the resource (that would be an SSRF risk); the link // reference is passed through as text so the agent can act on it. + // + // The generated `ResourceLink` requires BOTH `name` and `uri` (R17-F3b); + // an incomplete link is rejected (-32602) rather than silently rendered. + let name = block + .get("name") + .and_then(|v| v.as_str()) + .ok_or("resource_link content block missing required 'name'")?; let uri = block .get("uri") .and_then(|v| v.as_str()) - .ok_or("resource_link content block missing 'uri'")?; - let label = block - .get("name") - .and_then(|v| v.as_str()) - .or_else(|| block.get("title").and_then(|v| v.as_str())); - parts.push(match label { - Some(l) => format!("[{l}]({uri})"), - None => uri.to_string(), - }); + .ok_or("resource_link content block missing required 'uri'")?; + // Render as a Markdown link reference using the required `name` (matches + // the prior name-preferred labelling; the bare-uri fallback is gone since + // `name` is now mandatory). + parts.push(format!("[{name}]({uri})")); } Some(other) => { // Capability-gated variants (image / audio / embedded resource) that @@ -1423,13 +1426,16 @@ mod acp_conformance { }))) .unwrap(); assert_eq!(text, "see\n[X](file:///x)"); - // resource_link without a name/title renders the bare uri - let (_, text) = extract_prompt_params(Some(&json!({ - "sessionId": "sess_x", - "prompt": [{"type": "resource_link", "uri": "https://e/x"}] - }))) - .unwrap(); - assert_eq!(text, "https://e/x"); + // R17-F3b — `ResourceLink` requires `name`; a link missing it is rejected (-32602), + // no longer rendered as a bare uri. + assert!( + extract_prompt_params(Some(&json!({ + "sessionId": "sess_x", + "prompt": [{"type": "resource_link", "uri": "https://e/x"}] + }))) + .is_err(), + "resource_link missing required 'name' must be rejected" + ); // resource_link missing its required uri → error assert!(extract_prompt_params(Some(&json!({ "sessionId": "sess_x", From c0cb2f1f564aedd6b5f11e001dd6d0001f414437 Mon Sep 17 00:00:00 2001 From: Brett Chien Date: Thu, 23 Jul 2026 16:57:45 +0800 Subject: [PATCH 49/49] fix(acp): don't empty-success a request-shaped session/cancel (R17-F3c) ACP defines `session/cancel` as notification-only. A request-shaped cancel (with an `id`) was being acknowledged with `success({})`, which contradicts the ADR's "No response" contract and falsely implies cancel is a valid request method. Extract `handle_session_cancel`: the notification form still fires the session's cancel signal with no response; a request-shaped cancel is now rejected -32600 invalid request and does not fire. Tests: cancel with an id -> -32600 (no empty-success frame); notification -> no frame + fires. Co-Authored-By: Claude Opus 4.8 --- .../openab-gateway/src/adapters/acp_server.rs | 99 +++++++++++++++---- 1 file changed, 80 insertions(+), 19 deletions(-) diff --git a/crates/openab-gateway/src/adapters/acp_server.rs b/crates/openab-gateway/src/adapters/acp_server.rs index c42be44d7..18c2b2cca 100644 --- a/crates/openab-gateway/src/adapters/acp_server.rs +++ b/crates/openab-gateway/src/adapters/acp_server.rs @@ -674,25 +674,11 @@ async fn handle_acp_connection(state: Arc, socket: WebSocket) { prompt_tasks.push(handle); } "session/cancel" => { - // Per ACP, session/cancel is a one-way NOTIFICATION — no response. - // Fire the session's cancel signal; the in-flight prompt observes - // it, cleans up, and returns stopReason:"cancelled" to the prompt's - // own request id. - let sess_key = req - .params - .as_ref() - .and_then(|p| p.get("sessionId")) - .and_then(|v| v.as_str()); - if let Some(k) = sess_key { - let notify = sessions.lock().await.get(k).and_then(|s| s.cancel.clone()); - if let Some(n) = notify { - n.notify_one(); - } - } - // `session/cancel` is a notification: no response when sent as one. If a - // client sent it as a request (with an id), acknowledge with an empty result. - if !is_notification { - let resp = JsonRpcResponse::success(id, json!({})); + // Notification form fires the cancel signal (no response); a request-shaped + // cancel is rejected -32600 rather than acked with an empty success (R17-F3c). + if let Some(resp) = + handle_session_cancel(&sessions, id, req.params.as_ref(), is_notification).await + { let _ = out_tx.send(serde_json::to_string(&resp).unwrap()); } } @@ -898,6 +884,35 @@ async fn handle_session_resume( JsonRpcResponse::success(id, json!({})) } +/// Handle `session/cancel`. Per ACP it is a one-way NOTIFICATION: the notification form +/// (no `id`) fires the session's cancel signal — the in-flight prompt observes it, cleans +/// up, and returns `stopReason:"cancelled"` to the prompt's own request id — and produces +/// no response (`None`). A request-shaped cancel (with an `id`) is a protocol violation: it +/// is rejected with -32600 invalid request and does NOT fire the signal, rather than being +/// acknowledged with an empty success frame (R17-F3c). +async fn handle_session_cancel( + sessions: &Arc>>, + id: Value, + params: Option<&Value>, + is_notification: bool, +) -> Option { + if !is_notification { + return Some(JsonRpcResponse::error( + id, + -32600, + "session/cancel is a notification and must not carry an id", + )); + } + let sess_key = params.and_then(|p| p.get("sessionId")).and_then(|v| v.as_str()); + if let Some(k) = sess_key { + let notify = sessions.lock().await.get(k).and_then(|s| s.cancel.clone()); + if let Some(n) = notify { + n.notify_one(); + } + } + None +} + /// Derive the deterministic `channel_id` (`acp_`) from a client-supplied /// `sessionId` (`sess_`). Returns `None` if malformed — the uuid must /// parse, which keeps a resumed channel inside the `acp_` namespace and rejects @@ -1935,4 +1950,50 @@ mod acp_review_fixes { assert_eq!(chunks[0], "hello world"); assert_eq!(final_stop.as_deref(), Some("end_turn"), "a completed turn ends end_turn"); } + + // R17-F3c — a request-shaped `session/cancel` (id present) must NOT be acknowledged with + // an empty success frame. ACP defines cancel as notification-only, so a request form is a + // protocol violation → -32600 invalid request, and the cancel signal is not fired. + #[tokio::test] + async fn cancel_as_request_is_rejected_not_empty_success() { + let sessions = sessions_map(); + let params = json!({"sessionId": format!("sess_{}", Uuid::new_v4())}); + let resp = handle_session_cancel(&sessions, json!(42), Some(¶ms), false) + .await + .expect("a request-shaped cancel must produce a response, not silence"); + let v = serde_json::to_value(&resp).unwrap(); + assert_eq!(v["error"]["code"], json!(-32600), "request-shaped cancel must be -32600"); + assert_eq!(v["id"], json!(42)); + assert!( + v.get("result").is_none(), + "must NOT carry an empty-success result: {v}" + ); + } + + // R17-F3c — the notification form (no id) still fires the session's cancel signal and + // returns no response frame, unchanged. + #[tokio::test] + async fn cancel_as_notification_fires_signal_and_returns_no_response() { + let sessions = sessions_map(); + let sid = format!("sess_{}", Uuid::new_v4()); + let cancel = Arc::new(tokio::sync::Notify::new()); + sessions.lock().await.insert( + sid.clone(), + AcpSession { + channel_id: format!("acp_{}", Uuid::new_v4()), + busy: true, + cancel: Some(cancel.clone()), + }, + ); + let params = json!({"sessionId": sid}); + let resp = handle_session_cancel(&sessions, Value::Null, Some(¶ms), true).await; + assert!(resp.is_none(), "a notification cancel must produce no response frame"); + // notify_one stored a permit, so notified() resolves immediately — the signal fired. + assert!( + tokio::time::timeout(std::time::Duration::from_millis(200), cancel.notified()) + .await + .is_ok(), + "notification cancel must fire the session's cancel signal" + ); + } }