// What each side says it can do. A capability is a promise: whatever is advertised here is tested
// by the other side, and whatever is left out must never be used.
///|
/// Content kinds the agent accepts inside a prompt.
#derive(Eq)
pub(all) struct PromptCapabilities {
image : Bool
audio : Bool
embedded_context : Bool
meta : Json?
}
///|
pub extend PromptCapabilities with Eq::{equal, not_equal}
///|
/// Nothing supported: no images, no audio, no embedded context.
pub fn PromptCapabilities::none() -> PromptCapabilities {
{ image: false, audio: false, embedded_context: false, meta: None, }
}
///|
pub extend PromptCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for PromptCapabilities with fn to_json(self) {
json_of([
("image", json_bool(true_or_none(self.image))),
("audio", json_bool(true_or_none(self.audio))),
("embeddedContext", json_bool(true_or_none(self.embedded_context))),
("_meta", self.meta),
])
}
///|
fn true_or_none(value : Bool) -> Bool? {
if value {
Some(true)
} else {
None
}
}
///|
pub extend PromptCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for PromptCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
image: bool_member(fields, "image", path).unwrap_or(false),
audio: bool_member(fields, "audio", path).unwrap_or(false),
embedded_context: bool_member(fields, "embeddedContext", path).unwrap_or(
false,
),
meta: meta_of(fields, path),
}
}
///|
/// MCP transports the agent can connect to.
#derive(Eq)
pub(all) struct McpCapabilities {
http : Bool
sse : Bool
meta : Json?
}
///|
pub extend McpCapabilities with Eq::{equal, not_equal}
///|
/// No MCP transport supported.
pub fn McpCapabilities::none() -> McpCapabilities {
{ http: false, sse: false, meta: None, }
}
///|
pub extend McpCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for McpCapabilities with fn to_json(self) {
json_of([
("http", json_bool(true_or_none(self.http))),
("sse", json_bool(true_or_none(self.sse))),
("_meta", self.meta),
])
}
///|
pub extend McpCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for McpCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
http: bool_member(fields, "http", path).unwrap_or(false),
sse: bool_member(fields, "sse", path).unwrap_or(false),
meta: meta_of(fields, path),
}
}
///|
/// Session methods beyond `session/new`. Each flag is a promise to answer that method.
#derive(Eq)
pub(all) struct SessionCapabilities {
list : Bool
delete : Bool
additional_directories : Bool
resume_session : Bool
close : Bool
meta : Json?
}
///|
pub extend SessionCapabilities with Eq::{equal, not_equal}
///|
/// No session method beyond `session/new`.
pub fn SessionCapabilities::none() -> SessionCapabilities {
{
list: false,
delete: false,
additional_directories: false,
resume_session: false,
close: false,
meta: None,
}
}
///|
pub extend SessionCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for SessionCapabilities with fn to_json(self) {
json_of([
("list", presence(self.list)),
("delete", presence(self.delete)),
("additionalDirectories", presence(self.additional_directories)),
("resume", presence(self.resume_session)),
("close", presence(self.close)),
("_meta", self.meta),
])
}
///|
/// The schema marks a supported feature with an empty object rather than `true`.
fn presence(value : Bool) -> Json? {
if value {
Some(Json::empty_object())
} else {
None
}
}
///|
fn presence_of(fields : Map[String, Json], key : String) -> Bool {
match fields.get(key) {
Some(Object(_)) => true
Some(True) => true
_ => false
}
}
///|
pub extend SessionCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for SessionCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
list: presence_of(fields, "list"),
delete: presence_of(fields, "delete"),
additional_directories: presence_of(fields, "additionalDirectories"),
resume_session: presence_of(fields, "resume"),
close: presence_of(fields, "close"),
meta: meta_of(fields, path),
}
}
///|
/// Authentication the agent offers.
#derive(Eq)
pub(all) struct AgentAuthCapabilities {
logout : Bool
meta : Json?
}
///|
pub extend AgentAuthCapabilities with Eq::{equal, not_equal}
///|
/// No authentication step offered.
pub fn AgentAuthCapabilities::none() -> AgentAuthCapabilities {
{ logout: false, meta: None, }
}
///|
pub extend AgentAuthCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for AgentAuthCapabilities with fn to_json(self) {
json_of([
("logout", if self.logout { Some(Json::empty_object()) } else { None }),
("_meta", self.meta),
])
}
///|
pub extend AgentAuthCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for AgentAuthCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{ logout: presence_of(fields, "logout"), meta: meta_of(fields, path), }
}
///|
/// Everything the agent says it can do, sent back from `initialize`.
#derive(Eq)
pub(all) struct AgentCapabilities {
load_session : Bool
prompt : PromptCapabilities
mcp : McpCapabilities
session : SessionCapabilities
auth : AgentAuthCapabilities?
meta : Json?
}
///|
pub extend AgentCapabilities with Eq::{equal, not_equal}
///|
/// An agent that supports only `session/new` and `session/prompt`.
pub fn AgentCapabilities::none() -> AgentCapabilities {
{
load_session: false,
prompt: PromptCapabilities::none(),
mcp: McpCapabilities::none(),
session: SessionCapabilities::none(),
auth: None,
meta: None,
}
}
///|
pub extend AgentCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for AgentCapabilities with fn to_json(self) {
json_of([
("loadSession", json_bool(true_or_none(self.load_session))),
("promptCapabilities", Some(write(self.prompt))),
("mcpCapabilities", Some(write(self.mcp))),
("sessionCapabilities", Some(write(self.session))),
("auth", self.auth.map(write)),
("_meta", self.meta),
])
}
///|
pub extend AgentCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for AgentCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
load_session: bool_member(fields, "loadSession", path).unwrap_or(false),
prompt: object_member(fields, "promptCapabilities", path).unwrap_or(
PromptCapabilities::none(),
),
mcp: object_member(fields, "mcpCapabilities", path).unwrap_or(
McpCapabilities::none(),
),
session: object_member(fields, "sessionCapabilities", path).unwrap_or(
SessionCapabilities::none(),
),
auth: object_member(fields, "auth", path),
meta: meta_of(fields, path),
}
}
///|
/// Files the client lets the agent read and write on its behalf.
#derive(Eq)
pub(all) struct FileSystemCapabilities {
read_text_file : Bool
write_text_file : Bool
meta : Json?
}
///|
pub extend FileSystemCapabilities with Eq::{equal, not_equal}
///|
/// No file access granted.
pub fn FileSystemCapabilities::none() -> FileSystemCapabilities {
{ read_text_file: false, write_text_file: false, meta: None, }
}
///|
pub extend FileSystemCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for FileSystemCapabilities with fn to_json(self) {
json_of([
("readTextFile", json_bool(true_or_none(self.read_text_file))),
("writeTextFile", json_bool(true_or_none(self.write_text_file))),
("_meta", self.meta),
])
}
///|
pub extend FileSystemCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for FileSystemCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
read_text_file: bool_member(fields, "readTextFile", path).unwrap_or(false),
write_text_file: bool_member(fields, "writeTextFile", path).unwrap_or(false),
meta: meta_of(fields, path),
}
}
///|
/// Whether the client runs terminal commands for the agent.
#derive(Eq)
pub(all) struct ClientAuthCapabilities {
terminal : Bool
meta : Json?
}
///|
pub extend ClientAuthCapabilities with Eq::{equal, not_equal}
///|
/// No terminal authentication offered by the client.
pub fn ClientAuthCapabilities::none() -> ClientAuthCapabilities {
{ terminal: false, meta: None, }
}
///|
pub extend ClientAuthCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for ClientAuthCapabilities with fn to_json(self) {
json_of([
("terminal", json_bool(true_or_none(self.terminal))),
("_meta", self.meta),
])
}
///|
pub extend ClientAuthCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ClientAuthCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
terminal: bool_member(fields, "terminal", path).unwrap_or(false),
meta: meta_of(fields, path),
}
}
///|
/// The client's support for supplementary session features.
#derive(Eq)
pub(all) struct ClientSessionCapabilities {
compaction : Bool
config_options : Bool
booleans : Bool
notices : Bool
meta : Json?
}
///|
pub extend ClientSessionCapabilities with Eq::{equal, not_equal}
///|
/// No supplementary session features.
pub fn ClientSessionCapabilities::none() -> ClientSessionCapabilities {
{
compaction: false,
config_options: false,
booleans: false,
notices: false,
meta: None,
}
}
///|
pub extend ClientSessionCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for ClientSessionCapabilities with fn to_json(self) {
json_of([
("compaction", presence(self.compaction)),
(
"configOptions",
if self.config_options {
Some(json_of([("boolean", presence(self.booleans))]))
} else {
None
},
),
("notices", presence(self.notices)),
("_meta", self.meta),
])
}
///|
pub extend ClientSessionCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ClientSessionCapabilities with fn from_json(
json,
path,
) {
let fields = expect_object(json, path)
let booleans = match field_of(fields, "configOptions", path) {
None => false
Some(value) =>
presence_of(
expect_object(value, path.add_key("configOptions")),
"boolean",
)
}
{
compaction: presence_of(fields, "compaction"),
config_options: fields.contains("configOptions"),
booleans,
notices: presence_of(fields, "notices"),
meta: meta_of(fields, path),
}
}
///|
/// Elicitation kinds the client can show.
#derive(Eq)
pub(all) struct ElicitationCapabilities {
form : Bool
url : Bool
meta : Json?
}
///|
pub extend ElicitationCapabilities with Eq::{equal, not_equal}
///|
/// No elicitation kind supported.
pub fn ElicitationCapabilities::none() -> ElicitationCapabilities {
{ form: false, url: false, meta: None, }
}
///|
pub extend ElicitationCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for ElicitationCapabilities with fn to_json(self) {
json_of([
("form", presence(self.form)),
("url", presence(self.url)),
("_meta", self.meta),
])
}
///|
pub extend ElicitationCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ElicitationCapabilities with fn from_json(
json,
path,
) {
let fields = expect_object(json, path)
{
form: presence_of(fields, "form"),
url: presence_of(fields, "url"),
meta: meta_of(fields, path),
}
}
///|
/// Everything the client says it can do, sent with `initialize`.
#derive(Eq)
pub(all) struct ClientCapabilities {
fs : FileSystemCapabilities
terminal : Bool
session : ClientSessionCapabilities?
auth : ClientAuthCapabilities?
elicitation : ElicitationCapabilities?
meta : Json?
}
///|
pub extend ClientCapabilities with Eq::{equal, not_equal}
///|
/// A client that reads and writes nothing, runs nothing, and answers no ask.
pub fn ClientCapabilities::none() -> ClientCapabilities {
{
fs: FileSystemCapabilities::none(),
terminal: false,
session: None,
auth: None,
elicitation: None,
meta: None,
}
}
///|
pub extend ClientCapabilities with @json.ToJson::{to_json}
///|
pub impl ToJson for ClientCapabilities with fn to_json(self) {
json_of([
("fs", Some(write(self.fs))),
("terminal", json_bool(true_or_none(self.terminal))),
("session", self.session.map(write)),
("auth", self.auth.map(write)),
("elicitation", self.elicitation.map(write)),
("_meta", self.meta),
])
}
///|
pub extend ClientCapabilities with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for ClientCapabilities with fn from_json(json, path) {
let fields = expect_object(json, path)
{
fs: object_member(fields, "fs", path).unwrap_or(
FileSystemCapabilities::none(),
),
terminal: bool_member(fields, "terminal", path).unwrap_or(false),
session: object_member(fields, "session", path),
auth: object_member(fields, "auth", path),
elicitation: object_member(fields, "elicitation", path),
meta: meta_of(fields, path),
}
}
///|
/// A name and version, for the log and the about box.
#derive(Eq)
pub(all) struct Implementation {
name : String
version : String
title : String?
meta : Json?
}
///|
pub extend Implementation with Eq::{equal, not_equal}
///|
/// A name and a version, which is all the protocol asks for.
pub fn Implementation::new(name : String, version : String) -> Implementation {
{ name, version, title: None, meta: None, }
}
///|
pub extend Implementation with @json.ToJson::{to_json}
///|
pub impl ToJson for Implementation with fn to_json(self) {
json_of([
("name", Some(Json::string(self.name))),
("version", Some(Json::string(self.version))),
("title", json_string(self.title)),
("_meta", self.meta),
])
}
///|
pub extend Implementation with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for Implementation with fn from_json(json, path) {
let fields = expect_object(json, path)
{
name: required_string(fields, "name", path),
version: required_string(fields, "version", path),
title: string_member(fields, "title", path),
meta: meta_of(fields, path),
}
}
///|
/// An authentication method the agent offers, one of two shapes tagged by `type` on the wire; the
/// agent-driven one carries no tag.
#derive(Eq)
pub(all) enum AuthMethod {
Terminal(AuthMethodTerminal)
Agent(AuthMethodAgent)
}
///|
pub extend AuthMethod with Eq::{equal, not_equal}
///|
/// The client runs a command to authenticate.
#derive(Eq)
pub(all) struct AuthMethodTerminal {
id : String
name : String
description : String?
args : Array[String]?
env : Map[String, String]?
meta : Json?
}
///|
pub extend AuthMethodTerminal with Eq::{equal, not_equal}
///|
pub extend AuthMethodTerminal with @json.ToJson::{to_json}
///|
pub impl ToJson for AuthMethodTerminal with fn to_json(self) {
json_of([
("id", Some(Json::string(self.id))),
("name", Some(Json::string(self.name))),
("description", json_string(self.description)),
("args", json_list(self.args, Json::string)),
(
"env",
self.env.map(env => {
let out : Map[String, Json] = Map([])
env.each(fn(key, value) { out[key] = Json::string(value) })
Json::object(out)
}),
),
("_meta", self.meta),
])
}
///|
pub extend AuthMethodTerminal with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for AuthMethodTerminal with fn from_json(json, path) {
let fields = expect_object(json, path)
let env = match field_of(fields, "env", path) {
None => None
Some(value) => {
let values = expect_object(value, path.add_key("env"))
let out : Map[String, String] = Map([])
for entry in values.iter() {
let (key, item) = entry
out[key] = text_of(item, path.add_key("env").add_key(key))
}
Some(out)
}
}
{
id: required_string(fields, "id", path),
name: required_string(fields, "name", path),
description: string_member(fields, "description", path),
args: list_member(fields, "args", path, (value, at) => text_of(value, at)),
env,
meta: meta_of(fields, path),
}
}
///|
/// The agent runs the flow itself once `authenticate` is called.
#derive(Eq)
pub(all) struct AuthMethodAgent {
id : String
name : String
description : String?
meta : Json?
}
///|
pub extend AuthMethodAgent with Eq::{equal, not_equal}
///|
pub extend AuthMethodAgent with @json.ToJson::{to_json}
///|
pub impl ToJson for AuthMethodAgent with fn to_json(self) {
json_of([
("id", Some(Json::string(self.id))),
("name", Some(Json::string(self.name))),
("description", json_string(self.description)),
("_meta", self.meta),
])
}
///|
pub extend AuthMethodAgent with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for AuthMethodAgent with fn from_json(json, path) {
let fields = expect_object(json, path)
{
id: required_string(fields, "id", path),
name: required_string(fields, "name", path),
description: string_member(fields, "description", path),
meta: meta_of(fields, path),
}
}
///|
pub extend AuthMethod with @json.ToJson::{to_json}
///|
pub impl ToJson for AuthMethod with fn to_json(self) {
match self {
Terminal(terminal) => json_tagged(write(terminal), "type", "terminal")
Agent(agent) => write(agent)
}
}
///|
pub extend AuthMethod with @json.FromJson::{from_json}
///|
pub impl @json.FromJson for AuthMethod with fn from_json(json, path) {
let fields = expect_object(json, path)
if string_member(fields, "type", path) == Some("terminal") {
Terminal(read(json, path))
} else {
Agent(read(json, path))
}
}