use std::{path::PathBuf, sync::Arc};
use derive_more::{Display, From};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta,
ProtocolVersion, SessionId,
};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct InitializeRequest {
pub protocol_version: ProtocolVersion,
#[serde(default)]
pub client_capabilities: ClientCapabilities,
#[serde(skip_serializing_if = "Option::is_none")]
pub client_info: Option<Implementation>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl InitializeRequest {
#[must_use]
pub fn new(protocol_version: ProtocolVersion) -> Self {
Self {
protocol_version,
client_capabilities: ClientCapabilities::default(),
client_info: None,
meta: None,
}
}
#[must_use]
pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
self.client_capabilities = client_capabilities;
self
}
#[must_use]
pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
self.client_info = client_info.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct InitializeResponse {
pub protocol_version: ProtocolVersion,
#[serde(default)]
pub agent_capabilities: AgentCapabilities,
#[serde(default)]
pub auth_methods: Vec<AuthMethod>,
#[serde(skip_serializing_if = "Option::is_none")]
pub agent_info: Option<Implementation>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl InitializeResponse {
#[must_use]
pub fn new(protocol_version: ProtocolVersion) -> Self {
Self {
protocol_version,
agent_capabilities: AgentCapabilities::default(),
auth_methods: vec![],
agent_info: None,
meta: None,
}
}
#[must_use]
pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
self.agent_capabilities = agent_capabilities;
self
}
#[must_use]
pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
self.auth_methods = auth_methods;
self
}
#[must_use]
pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
self.agent_info = agent_info.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct Implementation {
pub name: String,
pub title: Option<String>,
pub version: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl Implementation {
pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
Self {
name: name.into(),
title: None,
version: version.into(),
meta: None,
}
}
#[must_use]
pub fn title(mut self, title: impl IntoOption<String>) -> Self {
self.title = title.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct AuthenticateRequest {
pub method_id: AuthMethodId,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl AuthenticateRequest {
#[must_use]
pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
Self {
method_id: method_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
#[non_exhaustive]
pub struct AuthenticateResponse {
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl AuthenticateResponse {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct AuthMethodId(pub Arc<str>);
impl AuthMethodId {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct AuthMethod {
pub id: AuthMethodId,
pub name: String,
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl AuthMethod {
pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
Self {
id: id.into(),
name: name.into(),
description: None,
meta: None,
}
}
#[must_use]
pub fn description(mut self, description: impl IntoOption<String>) -> Self {
self.description = description.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct NewSessionRequest {
pub cwd: PathBuf,
pub mcp_servers: Vec<McpServer>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl NewSessionRequest {
pub fn new(cwd: impl Into<PathBuf>) -> Self {
Self {
cwd: cwd.into(),
mcp_servers: vec![],
meta: None,
}
}
#[must_use]
pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
self.mcp_servers = mcp_servers;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct NewSessionResponse {
pub session_id: SessionId,
#[serde(skip_serializing_if = "Option::is_none")]
pub modes: Option<SessionModeState>,
#[cfg(feature = "unstable_session_model")]
#[serde(skip_serializing_if = "Option::is_none")]
pub models: Option<SessionModelState>,
#[serde(skip_serializing_if = "Option::is_none")]
pub config_options: Option<Vec<SessionConfigOption>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl NewSessionResponse {
#[must_use]
pub fn new(session_id: impl Into<SessionId>) -> Self {
Self {
session_id: session_id.into(),
modes: None,
#[cfg(feature = "unstable_session_model")]
models: None,
config_options: None,
meta: None,
}
}
#[must_use]
pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
self.modes = modes.into_option();
self
}
#[cfg(feature = "unstable_session_model")]
#[must_use]
pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
self.models = models.into_option();
self
}
#[must_use]
pub fn config_options(
mut self,
config_options: impl IntoOption<Vec<SessionConfigOption>>,
) -> Self {
self.config_options = config_options.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct LoadSessionRequest {
pub mcp_servers: Vec<McpServer>,
pub cwd: PathBuf,
pub session_id: SessionId,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl LoadSessionRequest {
pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
Self {
mcp_servers: vec![],
cwd: cwd.into(),
session_id: session_id.into(),
meta: None,
}
}
#[must_use]
pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
self.mcp_servers = mcp_servers;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct LoadSessionResponse {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub modes: Option<SessionModeState>,
#[cfg(feature = "unstable_session_model")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub models: Option<SessionModelState>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub config_options: Option<Vec<SessionConfigOption>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl LoadSessionResponse {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
self.modes = modes.into_option();
self
}
#[cfg(feature = "unstable_session_model")]
#[must_use]
pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
self.models = models.into_option();
self
}
#[must_use]
pub fn config_options(
mut self,
config_options: impl IntoOption<Vec<SessionConfigOption>>,
) -> Self {
self.config_options = config_options.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_fork")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ForkSessionRequest {
pub session_id: SessionId,
pub cwd: PathBuf,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub mcp_servers: Vec<McpServer>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_fork")]
impl ForkSessionRequest {
pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
Self {
session_id: session_id.into(),
cwd: cwd.into(),
mcp_servers: vec![],
meta: None,
}
}
#[must_use]
pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
self.mcp_servers = mcp_servers;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_fork")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ForkSessionResponse {
pub session_id: SessionId,
#[serde(skip_serializing_if = "Option::is_none")]
pub modes: Option<SessionModeState>,
#[cfg(feature = "unstable_session_model")]
#[serde(skip_serializing_if = "Option::is_none")]
pub models: Option<SessionModelState>,
#[serde(skip_serializing_if = "Option::is_none")]
pub config_options: Option<Vec<SessionConfigOption>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_fork")]
impl ForkSessionResponse {
#[must_use]
pub fn new(session_id: impl Into<SessionId>) -> Self {
Self {
session_id: session_id.into(),
modes: None,
#[cfg(feature = "unstable_session_model")]
models: None,
config_options: None,
meta: None,
}
}
#[must_use]
pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
self.modes = modes.into_option();
self
}
#[cfg(feature = "unstable_session_model")]
#[must_use]
pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
self.models = models.into_option();
self
}
#[must_use]
pub fn config_options(
mut self,
config_options: impl IntoOption<Vec<SessionConfigOption>>,
) -> Self {
self.config_options = config_options.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_resume")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ResumeSessionRequest {
pub session_id: SessionId,
pub cwd: PathBuf,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub mcp_servers: Vec<McpServer>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_resume")]
impl ResumeSessionRequest {
pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
Self {
session_id: session_id.into(),
cwd: cwd.into(),
mcp_servers: vec![],
meta: None,
}
}
#[must_use]
pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
self.mcp_servers = mcp_servers;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_resume")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ResumeSessionResponse {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub modes: Option<SessionModeState>,
#[cfg(feature = "unstable_session_model")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub models: Option<SessionModelState>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub config_options: Option<Vec<SessionConfigOption>>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_resume")]
impl ResumeSessionResponse {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
self.modes = modes.into_option();
self
}
#[cfg(feature = "unstable_session_model")]
#[must_use]
pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
self.models = models.into_option();
self
}
#[must_use]
pub fn config_options(
mut self,
config_options: impl IntoOption<Vec<SessionConfigOption>>,
) -> Self {
self.config_options = config_options.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_list")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ListSessionsRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub cwd: Option<PathBuf>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_list")]
impl ListSessionsRequest {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
self.cwd = cwd.into_option();
self
}
#[must_use]
pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
self.cursor = cursor.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_list")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ListSessionsResponse {
pub sessions: Vec<SessionInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_list")]
impl ListSessionsResponse {
#[must_use]
pub fn new(sessions: Vec<SessionInfo>) -> Self {
Self {
sessions,
next_cursor: None,
meta: None,
}
}
#[must_use]
pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
self.next_cursor = next_cursor.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_list")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionInfo {
pub session_id: SessionId,
pub cwd: PathBuf,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_list")]
impl SessionInfo {
pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
Self {
session_id: session_id.into(),
cwd: cwd.into(),
title: None,
updated_at: None,
meta: None,
}
}
#[must_use]
pub fn title(mut self, title: impl IntoOption<String>) -> Self {
self.title = title.into_option();
self
}
#[must_use]
pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
self.updated_at = updated_at.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionModeState {
pub current_mode_id: SessionModeId,
pub available_modes: Vec<SessionMode>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SessionModeState {
#[must_use]
pub fn new(
current_mode_id: impl Into<SessionModeId>,
available_modes: Vec<SessionMode>,
) -> Self {
Self {
current_mode_id: current_mode_id.into(),
available_modes,
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionMode {
pub id: SessionModeId,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SessionMode {
pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
Self {
id: id.into(),
name: name.into(),
description: None,
meta: None,
}
}
#[must_use]
pub fn description(mut self, description: impl IntoOption<String>) -> Self {
self.description = description.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct SessionModeId(pub Arc<str>);
impl SessionModeId {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SetSessionModeRequest {
pub session_id: SessionId,
pub mode_id: SessionModeId,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SetSessionModeRequest {
#[must_use]
pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
Self {
session_id: session_id.into(),
mode_id: mode_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SetSessionModeResponse {
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SetSessionModeResponse {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct SessionConfigId(pub Arc<str>);
impl SessionConfigId {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct SessionConfigValueId(pub Arc<str>);
impl SessionConfigValueId {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct SessionConfigGroupId(pub Arc<str>);
impl SessionConfigGroupId {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionConfigSelectOption {
pub value: SessionConfigValueId,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SessionConfigSelectOption {
#[must_use]
pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
Self {
value: value.into(),
name: name.into(),
description: None,
meta: None,
}
}
#[must_use]
pub fn description(mut self, description: impl IntoOption<String>) -> Self {
self.description = description.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionConfigSelectGroup {
pub group: SessionConfigGroupId,
pub name: String,
pub options: Vec<SessionConfigSelectOption>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SessionConfigSelectGroup {
#[must_use]
pub fn new(
group: impl Into<SessionConfigGroupId>,
name: impl Into<String>,
options: Vec<SessionConfigSelectOption>,
) -> Self {
Self {
group: group.into(),
name: name.into(),
options,
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(untagged)]
#[non_exhaustive]
pub enum SessionConfigSelectOptions {
Ungrouped(Vec<SessionConfigSelectOption>),
Grouped(Vec<SessionConfigSelectGroup>),
}
impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
fn from(options: Vec<SessionConfigSelectOption>) -> Self {
SessionConfigSelectOptions::Ungrouped(options)
}
}
impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
SessionConfigSelectOptions::Grouped(groups)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionConfigSelect {
pub current_value: SessionConfigValueId,
pub options: SessionConfigSelectOptions,
}
impl SessionConfigSelect {
#[must_use]
pub fn new(
current_value: impl Into<SessionConfigValueId>,
options: impl Into<SessionConfigSelectOptions>,
) -> Self {
Self {
current_value: current_value.into(),
options: options.into(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum SessionConfigOptionCategory {
Mode,
Model,
ThoughtLevel,
#[serde(untagged)]
Other(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(tag = "type", rename_all = "snake_case")]
#[schemars(extend("discriminator" = {"propertyName": "type"}))]
#[non_exhaustive]
pub enum SessionConfigKind {
Select(SessionConfigSelect),
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionConfigOption {
pub id: SessionConfigId,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub category: Option<SessionConfigOptionCategory>,
#[serde(flatten)]
pub kind: SessionConfigKind,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SessionConfigOption {
#[must_use]
pub fn new(
id: impl Into<SessionConfigId>,
name: impl Into<String>,
kind: SessionConfigKind,
) -> Self {
Self {
id: id.into(),
name: name.into(),
description: None,
category: None,
kind,
meta: None,
}
}
#[must_use]
pub fn select(
id: impl Into<SessionConfigId>,
name: impl Into<String>,
current_value: impl Into<SessionConfigValueId>,
options: impl Into<SessionConfigSelectOptions>,
) -> Self {
Self::new(
id,
name,
SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
)
}
#[must_use]
pub fn description(mut self, description: impl IntoOption<String>) -> Self {
self.description = description.into_option();
self
}
#[must_use]
pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
self.category = category.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SetSessionConfigOptionRequest {
pub session_id: SessionId,
pub config_id: SessionConfigId,
pub value: SessionConfigValueId,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SetSessionConfigOptionRequest {
#[must_use]
pub fn new(
session_id: impl Into<SessionId>,
config_id: impl Into<SessionConfigId>,
value: impl Into<SessionConfigValueId>,
) -> Self {
Self {
session_id: session_id.into(),
config_id: config_id.into(),
value: value.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SetSessionConfigOptionResponse {
pub config_options: Vec<SessionConfigOption>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SetSessionConfigOptionResponse {
#[must_use]
pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
Self {
config_options,
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(tag = "type", rename_all = "snake_case")]
#[non_exhaustive]
pub enum McpServer {
Http(McpServerHttp),
Sse(McpServerSse),
#[serde(untagged)]
Stdio(McpServerStdio),
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct McpServerHttp {
pub name: String,
pub url: String,
pub headers: Vec<HttpHeader>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl McpServerHttp {
pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
Self {
name: name.into(),
url: url.into(),
headers: Vec::new(),
meta: None,
}
}
#[must_use]
pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
self.headers = headers;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct McpServerSse {
pub name: String,
pub url: String,
pub headers: Vec<HttpHeader>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl McpServerSse {
pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
Self {
name: name.into(),
url: url.into(),
headers: Vec::new(),
meta: None,
}
}
#[must_use]
pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
self.headers = headers;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct McpServerStdio {
pub name: String,
pub command: PathBuf,
pub args: Vec<String>,
pub env: Vec<EnvVariable>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl McpServerStdio {
pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
Self {
name: name.into(),
command: command.into(),
args: Vec::new(),
env: Vec::new(),
meta: None,
}
}
#[must_use]
pub fn args(mut self, args: Vec<String>) -> Self {
self.args = args;
self
}
#[must_use]
pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
self.env = env;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct EnvVariable {
pub name: String,
pub value: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl EnvVariable {
pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
Self {
name: name.into(),
value: value.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct HttpHeader {
pub name: String,
pub value: String,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl HttpHeader {
pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
Self {
name: name.into(),
value: value.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct PromptRequest {
pub session_id: SessionId,
pub prompt: Vec<ContentBlock>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl PromptRequest {
#[must_use]
pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
Self {
session_id: session_id.into(),
prompt,
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct PromptResponse {
pub stop_reason: StopReason,
#[cfg(feature = "unstable_session_usage")]
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<Usage>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl PromptResponse {
#[must_use]
pub fn new(stop_reason: StopReason) -> Self {
Self {
stop_reason,
#[cfg(feature = "unstable_session_usage")]
usage: None,
meta: None,
}
}
#[cfg(feature = "unstable_session_usage")]
#[must_use]
pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
self.usage = usage.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum StopReason {
EndTurn,
MaxTokens,
MaxTurnRequests,
Refusal,
Cancelled,
}
#[cfg(feature = "unstable_session_usage")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct Usage {
pub total_tokens: u64,
pub input_tokens: u64,
pub output_tokens: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub thought_tokens: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cached_read_tokens: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cached_write_tokens: Option<u64>,
}
#[cfg(feature = "unstable_session_usage")]
impl Usage {
#[must_use]
pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
Self {
total_tokens,
input_tokens,
output_tokens,
thought_tokens: None,
cached_read_tokens: None,
cached_write_tokens: None,
}
}
#[must_use]
pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
self.thought_tokens = thought_tokens.into_option();
self
}
#[must_use]
pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
self.cached_read_tokens = cached_read_tokens.into_option();
self
}
#[must_use]
pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
self.cached_write_tokens = cached_write_tokens.into_option();
self
}
}
#[cfg(feature = "unstable_session_model")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SessionModelState {
pub current_model_id: ModelId,
pub available_models: Vec<ModelInfo>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_model")]
impl SessionModelState {
#[must_use]
pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
Self {
current_model_id: current_model_id.into(),
available_models,
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_model")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
#[serde(transparent)]
#[from(Arc<str>, String, &'static str)]
#[non_exhaustive]
pub struct ModelId(pub Arc<str>);
#[cfg(feature = "unstable_session_model")]
impl ModelId {
pub fn new(id: impl Into<Arc<str>>) -> Self {
Self(id.into())
}
}
#[cfg(feature = "unstable_session_model")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct ModelInfo {
pub model_id: ModelId,
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_model")]
impl ModelInfo {
pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
Self {
model_id: model_id.into(),
name: name.into(),
description: None,
meta: None,
}
}
#[must_use]
pub fn description(mut self, description: impl IntoOption<String>) -> Self {
self.description = description.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_model")]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SetSessionModelRequest {
pub session_id: SessionId,
pub model_id: ModelId,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_model")]
impl SetSessionModelRequest {
#[must_use]
pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
Self {
session_id: session_id.into(),
model_id: model_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_model")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct SetSessionModelResponse {
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_model")]
impl SetSessionModelResponse {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct AgentCapabilities {
#[serde(default)]
pub load_session: bool,
#[serde(default)]
pub prompt_capabilities: PromptCapabilities,
#[serde(default)]
pub mcp_capabilities: McpCapabilities,
#[serde(default)]
pub session_capabilities: SessionCapabilities,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl AgentCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn load_session(mut self, load_session: bool) -> Self {
self.load_session = load_session;
self
}
#[must_use]
pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
self.prompt_capabilities = prompt_capabilities;
self
}
#[must_use]
pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
self.mcp_capabilities = mcp_capabilities;
self
}
#[must_use]
pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
self.session_capabilities = session_capabilities;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[non_exhaustive]
pub struct SessionCapabilities {
#[cfg(feature = "unstable_session_list")]
#[serde(skip_serializing_if = "Option::is_none")]
pub list: Option<SessionListCapabilities>,
#[cfg(feature = "unstable_session_fork")]
#[serde(skip_serializing_if = "Option::is_none")]
pub fork: Option<SessionForkCapabilities>,
#[cfg(feature = "unstable_session_resume")]
#[serde(skip_serializing_if = "Option::is_none")]
pub resume: Option<SessionResumeCapabilities>,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl SessionCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[cfg(feature = "unstable_session_list")]
#[must_use]
pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
self.list = list.into_option();
self
}
#[cfg(feature = "unstable_session_fork")]
#[must_use]
pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
self.fork = fork.into_option();
self
}
#[cfg(feature = "unstable_session_resume")]
#[must_use]
pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
self.resume = resume.into_option();
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_list")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[non_exhaustive]
pub struct SessionListCapabilities {
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_list")]
impl SessionListCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_fork")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[non_exhaustive]
pub struct SessionForkCapabilities {
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_fork")]
impl SessionForkCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(feature = "unstable_session_resume")]
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[non_exhaustive]
pub struct SessionResumeCapabilities {
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
#[cfg(feature = "unstable_session_resume")]
impl SessionResumeCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct PromptCapabilities {
#[serde(default)]
pub image: bool,
#[serde(default)]
pub audio: bool,
#[serde(default)]
pub embedded_context: bool,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl PromptCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn image(mut self, image: bool) -> Self {
self.image = image;
self
}
#[must_use]
pub fn audio(mut self, audio: bool) -> Self {
self.audio = audio;
self
}
#[must_use]
pub fn embedded_context(mut self, embedded_context: bool) -> Self {
self.embedded_context = embedded_context;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct McpCapabilities {
#[serde(default)]
pub http: bool,
#[serde(default)]
pub sse: bool,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl McpCapabilities {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn http(mut self, http: bool) -> Self {
self.http = http;
self
}
#[must_use]
pub fn sse(mut self, sse: bool) -> Self {
self.sse = sse;
self
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct AgentMethodNames {
pub initialize: &'static str,
pub authenticate: &'static str,
pub session_new: &'static str,
pub session_load: &'static str,
pub session_set_mode: &'static str,
pub session_set_config_option: &'static str,
pub session_prompt: &'static str,
pub session_cancel: &'static str,
#[cfg(feature = "unstable_session_model")]
pub session_set_model: &'static str,
#[cfg(feature = "unstable_session_list")]
pub session_list: &'static str,
#[cfg(feature = "unstable_session_fork")]
pub session_fork: &'static str,
#[cfg(feature = "unstable_session_resume")]
pub session_resume: &'static str,
}
pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
initialize: INITIALIZE_METHOD_NAME,
authenticate: AUTHENTICATE_METHOD_NAME,
session_new: SESSION_NEW_METHOD_NAME,
session_load: SESSION_LOAD_METHOD_NAME,
session_set_mode: SESSION_SET_MODE_METHOD_NAME,
session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
session_prompt: SESSION_PROMPT_METHOD_NAME,
session_cancel: SESSION_CANCEL_METHOD_NAME,
#[cfg(feature = "unstable_session_model")]
session_set_model: SESSION_SET_MODEL_METHOD_NAME,
#[cfg(feature = "unstable_session_list")]
session_list: SESSION_LIST_METHOD_NAME,
#[cfg(feature = "unstable_session_fork")]
session_fork: SESSION_FORK_METHOD_NAME,
#[cfg(feature = "unstable_session_resume")]
session_resume: SESSION_RESUME_METHOD_NAME,
};
pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
#[cfg(feature = "unstable_session_model")]
pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
#[cfg(feature = "unstable_session_list")]
pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
#[cfg(feature = "unstable_session_fork")]
pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
#[cfg(feature = "unstable_session_resume")]
pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
#[schemars(inline)]
#[non_exhaustive]
pub enum ClientRequest {
InitializeRequest(InitializeRequest),
AuthenticateRequest(AuthenticateRequest),
NewSessionRequest(NewSessionRequest),
LoadSessionRequest(LoadSessionRequest),
#[cfg(feature = "unstable_session_list")]
ListSessionsRequest(ListSessionsRequest),
#[cfg(feature = "unstable_session_fork")]
ForkSessionRequest(ForkSessionRequest),
#[cfg(feature = "unstable_session_resume")]
ResumeSessionRequest(ResumeSessionRequest),
SetSessionModeRequest(SetSessionModeRequest),
SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
PromptRequest(PromptRequest),
#[cfg(feature = "unstable_session_model")]
SetSessionModelRequest(SetSessionModelRequest),
ExtMethodRequest(ExtRequest),
}
impl ClientRequest {
#[must_use]
pub fn method(&self) -> &str {
match self {
Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
#[cfg(feature = "unstable_session_list")]
Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
#[cfg(feature = "unstable_session_fork")]
Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
#[cfg(feature = "unstable_session_resume")]
Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
#[cfg(feature = "unstable_session_model")]
Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
Self::ExtMethodRequest(ext_request) => &ext_request.method,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
#[schemars(inline)]
#[non_exhaustive]
pub enum AgentResponse {
InitializeResponse(InitializeResponse),
AuthenticateResponse(#[serde(default)] AuthenticateResponse),
NewSessionResponse(NewSessionResponse),
LoadSessionResponse(#[serde(default)] LoadSessionResponse),
#[cfg(feature = "unstable_session_list")]
ListSessionsResponse(ListSessionsResponse),
#[cfg(feature = "unstable_session_fork")]
ForkSessionResponse(ForkSessionResponse),
#[cfg(feature = "unstable_session_resume")]
ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
PromptResponse(PromptResponse),
#[cfg(feature = "unstable_session_model")]
SetSessionModelResponse(SetSessionModelResponse),
ExtMethodResponse(ExtResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
#[schemars(inline)]
#[non_exhaustive]
pub enum ClientNotification {
CancelNotification(CancelNotification),
ExtNotification(ExtNotification),
}
impl ClientNotification {
#[must_use]
pub fn method(&self) -> &str {
match self {
Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
Self::ExtNotification(ext_notification) => &ext_notification.method,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct CancelNotification {
pub session_id: SessionId,
#[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
pub meta: Option<Meta>,
}
impl CancelNotification {
#[must_use]
pub fn new(session_id: impl Into<SessionId>) -> Self {
Self {
session_id: session_id.into(),
meta: None,
}
}
#[must_use]
pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
self.meta = meta.into_option();
self
}
}
#[cfg(test)]
mod test_serialization {
use super::*;
use serde_json::json;
#[test]
fn test_mcp_server_stdio_serialization() {
let server = McpServer::Stdio(
McpServerStdio::new("test-server", "/usr/bin/server")
.args(vec!["--port".to_string(), "3000".to_string()])
.env(vec![EnvVariable::new("API_KEY", "secret123")]),
);
let json = serde_json::to_value(&server).unwrap();
assert_eq!(
json,
json!({
"name": "test-server",
"command": "/usr/bin/server",
"args": ["--port", "3000"],
"env": [
{
"name": "API_KEY",
"value": "secret123"
}
]
})
);
let deserialized: McpServer = serde_json::from_value(json).unwrap();
match deserialized {
McpServer::Stdio(McpServerStdio {
name,
command,
args,
env,
meta: _,
}) => {
assert_eq!(name, "test-server");
assert_eq!(command, PathBuf::from("/usr/bin/server"));
assert_eq!(args, vec!["--port", "3000"]);
assert_eq!(env.len(), 1);
assert_eq!(env[0].name, "API_KEY");
assert_eq!(env[0].value, "secret123");
}
_ => panic!("Expected Stdio variant"),
}
}
#[test]
fn test_mcp_server_http_serialization() {
let server = McpServer::Http(
McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
HttpHeader::new("Authorization", "Bearer token123"),
HttpHeader::new("Content-Type", "application/json"),
]),
);
let json = serde_json::to_value(&server).unwrap();
assert_eq!(
json,
json!({
"type": "http",
"name": "http-server",
"url": "https://api.example.com",
"headers": [
{
"name": "Authorization",
"value": "Bearer token123"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
})
);
let deserialized: McpServer = serde_json::from_value(json).unwrap();
match deserialized {
McpServer::Http(McpServerHttp {
name,
url,
headers,
meta: _,
}) => {
assert_eq!(name, "http-server");
assert_eq!(url, "https://api.example.com");
assert_eq!(headers.len(), 2);
assert_eq!(headers[0].name, "Authorization");
assert_eq!(headers[0].value, "Bearer token123");
assert_eq!(headers[1].name, "Content-Type");
assert_eq!(headers[1].value, "application/json");
}
_ => panic!("Expected Http variant"),
}
}
#[test]
fn test_mcp_server_sse_serialization() {
let server = McpServer::Sse(
McpServerSse::new("sse-server", "https://sse.example.com/events")
.headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
);
let json = serde_json::to_value(&server).unwrap();
assert_eq!(
json,
json!({
"type": "sse",
"name": "sse-server",
"url": "https://sse.example.com/events",
"headers": [
{
"name": "X-API-Key",
"value": "apikey456"
}
]
})
);
let deserialized: McpServer = serde_json::from_value(json).unwrap();
match deserialized {
McpServer::Sse(McpServerSse {
name,
url,
headers,
meta: _,
}) => {
assert_eq!(name, "sse-server");
assert_eq!(url, "https://sse.example.com/events");
assert_eq!(headers.len(), 1);
assert_eq!(headers[0].name, "X-API-Key");
assert_eq!(headers[0].value, "apikey456");
}
_ => panic!("Expected Sse variant"),
}
}
#[test]
fn test_session_config_option_category_known_variants() {
assert_eq!(
serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
json!("mode")
);
assert_eq!(
serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
json!("model")
);
assert_eq!(
serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
json!("thought_level")
);
assert_eq!(
serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
SessionConfigOptionCategory::Mode
);
assert_eq!(
serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
SessionConfigOptionCategory::Model
);
assert_eq!(
serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
SessionConfigOptionCategory::ThoughtLevel
);
}
#[test]
fn test_session_config_option_category_unknown_variants() {
let unknown: SessionConfigOptionCategory =
serde_json::from_str("\"some_future_category\"").unwrap();
assert_eq!(
unknown,
SessionConfigOptionCategory::Other("some_future_category".to_string())
);
let json = serde_json::to_value(&unknown).unwrap();
assert_eq!(json, json!("some_future_category"));
}
#[test]
fn test_session_config_option_category_custom_categories() {
let custom: SessionConfigOptionCategory =
serde_json::from_str("\"_my_custom_category\"").unwrap();
assert_eq!(
custom,
SessionConfigOptionCategory::Other("_my_custom_category".to_string())
);
let json = serde_json::to_value(&custom).unwrap();
assert_eq!(json, json!("_my_custom_category"));
let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
assert_eq!(
deserialized,
SessionConfigOptionCategory::Other("_my_custom_category".to_string())
);
}
}