// capabilities.mbt — upstream `src/capabilities.ts` mirror: the
// `LodyExtensionCapabilities` advertisement mounted at
// `InitializeResponse.agentCapabilities._meta.lody`. Nine optional feature
// keys; each capability carries its own integer `version` (all version 1 in
// this contract revision), sharing the `LodyVersionOneCapability` base.
//
// Wire key naming: the upstream repo ships TypeScript types only and gives no
// evidence for on-wire JSON key serialization, so the TS camelCase keys are
// emitted verbatim — awaiting on-wire verification.
///|
/// `LodyVersionOneCapability` — the `{ version: 1 }` base shared by every
/// feature key.
pub(all) struct LodyVersionOneCapability {
version : Int
} derive(Eq, Debug)
///|
pub fn LodyVersionOneCapability::version_one() -> LodyVersionOneCapability {
LodyVersionOneCapability::{ version: 1, }
}
///|
pub fn LodyVersionOneCapability::to_json(
self : LodyVersionOneCapability,
) -> Json {
Json::object(
Map::from_array([("version", Json::number(self.version.to_double()))]),
)
}
///|
pub fn LodyVersionOneCapability::from_json(
raw : Json,
) -> Result[LodyVersionOneCapability, String] {
try {
let ctx = "lody.capabilities.versionOne"
let fields = object_fields(raw, ctx)
let version = req_int(fields, ctx, "version")
guard version == 1 else {
raise DecodeError::Msg(
"\{ctx}: unsupported version \{version} (expected 1)",
)
}
Ok(LodyVersionOneCapability::{ version, })
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `LodyRateLimitsCapability` — supports rate-limit notifications;
/// `query: true` additionally advertises that `_lody/rate_limits/get` is
/// answerable.
pub(all) struct LodyRateLimitsCapability {
version : Int
query : Bool?
} derive(Eq, Debug)
///|
pub fn LodyRateLimitsCapability::to_json(
self : LodyRateLimitsCapability,
) -> Json {
let pairs : Array[(String, Json)] = [
("version", Json::number(self.version.to_double())),
]
match self.query {
Some(v) => pairs.push(("query", Json::boolean(v)))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn LodyRateLimitsCapability::from_json(
raw : Json,
) -> Result[LodyRateLimitsCapability, String] {
try {
let ctx = "lody.capabilities.rateLimits"
let fields = object_fields(raw, ctx)
let version = req_int(fields, ctx, "version")
guard version == 1 else {
raise DecodeError::Msg(
"\{ctx}: unsupported version \{version} (expected 1)",
)
}
Ok(LodyRateLimitsCapability::{
version,
query: opt_bool(fields, ctx, "query"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `LodySteeringCapability` — supports `_lody/session/steer`; declares the
/// transport, upstream-turn policy, and config-effectiveness policy.
pub(all) struct LodySteeringCapability {
version : Int
transport : LodySteeringTransport
upstream_turn : LodySteeringUpstreamTurn
config_policy : LodySteeringConfigPolicy
} derive(Eq, Debug)
///|
pub fn LodySteeringCapability::to_json(self : LodySteeringCapability) -> Json {
Json::object(
Map::from_array([
("version", Json::number(self.version.to_double())),
("transport", Json::string(self.transport.to_wire())),
("upstreamTurn", Json::string(self.upstream_turn.to_wire())),
("configPolicy", Json::string(self.config_policy.to_wire())),
]),
)
}
///|
pub fn LodySteeringCapability::from_json(
raw : Json,
) -> Result[LodySteeringCapability, String] {
try {
let ctx = "lody.capabilities.steering"
let fields = object_fields(raw, ctx)
let version = req_int(fields, ctx, "version")
guard version == 1 else {
raise DecodeError::Msg(
"\{ctx}: unsupported version \{version} (expected 1)",
)
}
Ok(LodySteeringCapability::{
version,
transport: wire_of(
ctx,
"transport",
LodySteeringTransport::of_wire(req_string(fields, ctx, "transport")),
),
upstream_turn: wire_of(
ctx,
"upstreamTurn",
LodySteeringUpstreamTurn::of_wire(
req_string(fields, ctx, "upstreamTurn"),
),
),
config_policy: wire_of(
ctx,
"configPolicy",
LodySteeringConfigPolicy::of_wire(
req_string(fields, ctx, "configPolicy"),
),
),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `LodyTaskCapability` — tool_call envelopes may carry `_meta.lody.task`;
/// `background` / `scheduled` declare the supported task subclasses.
pub(all) struct LodyTaskCapability {
version : Int
background : Bool?
scheduled : Bool?
} derive(Eq, Debug)
///|
pub fn LodyTaskCapability::to_json(self : LodyTaskCapability) -> Json {
let pairs : Array[(String, Json)] = [
("version", Json::number(self.version.to_double())),
]
match self.background {
Some(v) => pairs.push(("background", Json::boolean(v)))
None => ()
}
match self.scheduled {
Some(v) => pairs.push(("scheduled", Json::boolean(v)))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn LodyTaskCapability::from_json(
raw : Json,
) -> Result[LodyTaskCapability, String] {
try {
let ctx = "lody.capabilities.tasks"
let fields = object_fields(raw, ctx)
let version = req_int(fields, ctx, "version")
guard version == 1 else {
raise DecodeError::Msg(
"\{ctx}: unsupported version \{version} (expected 1)",
)
}
Ok(LodyTaskCapability::{
version,
background: opt_bool(fields, ctx, "background"),
scheduled: opt_bool(fields, ctx, "scheduled"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `LodySubagentCapability` — supports subagent lifecycle (`lifecycle` is
/// required); `list` / `cancel` / `output` declare the three query methods.
pub(all) struct LodySubagentCapability {
version : Int
lifecycle : Bool
list : Bool?
cancel : Bool?
output : Bool?
} derive(Eq, Debug)
///|
pub fn LodySubagentCapability::to_json(self : LodySubagentCapability) -> Json {
let pairs : Array[(String, Json)] = [
("version", Json::number(self.version.to_double())),
("lifecycle", Json::boolean(self.lifecycle)),
]
match self.list {
Some(v) => pairs.push(("list", Json::boolean(v)))
None => ()
}
match self.cancel {
Some(v) => pairs.push(("cancel", Json::boolean(v)))
None => ()
}
match self.output {
Some(v) => pairs.push(("output", Json::boolean(v)))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn LodySubagentCapability::from_json(
raw : Json,
) -> Result[LodySubagentCapability, String] {
try {
let ctx = "lody.capabilities.subagents"
let fields = object_fields(raw, ctx)
let version = req_int(fields, ctx, "version")
guard version == 1 else {
raise DecodeError::Msg(
"\{ctx}: unsupported version \{version} (expected 1)",
)
}
Ok(LodySubagentCapability::{
version,
lifecycle: req_bool(fields, ctx, "lifecycle"),
list: opt_bool(fields, ctx, "list"),
cancel: opt_bool(fields, ctx, "cancel"),
output: opt_bool(fields, ctx, "output"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `LodyGoalCapability` — supports goal management and `_lody/session/goal`;
/// `actions` declares the supported verb set.
pub(all) struct LodyGoalCapability {
version : Int
actions : Array[LodyGoalAction]
} derive(Eq, Debug)
///|
pub fn LodyGoalCapability::to_json(self : LodyGoalCapability) -> Json {
Json::object(
Map::from_array([
("version", Json::number(self.version.to_double())),
(
"actions",
Json::array(
self.actions.map(fn(action) { Json::string(action.to_wire()) }),
),
),
]),
)
}
///|
pub fn LodyGoalCapability::from_json(
raw : Json,
) -> Result[LodyGoalCapability, String] {
try {
let ctx = "lody.capabilities.goal"
let fields = object_fields(raw, ctx)
let version = req_int(fields, ctx, "version")
guard version == 1 else {
raise DecodeError::Msg(
"\{ctx}: unsupported version \{version} (expected 1)",
)
}
let actions : Array[LodyGoalAction] = []
for item in req_array(fields, ctx, "actions") {
match item {
Json::String(wire) =>
match LodyGoalAction::of_wire(wire) {
Ok(action) => actions.push(action)
Err(message) =>
raise DecodeError::Msg("\{ctx}: field \"actions\": \{message}")
}
_ =>
raise DecodeError::Msg(
"\{ctx}: field \"actions\" must contain strings",
)
}
}
Ok(LodyGoalCapability::{ version, actions, })
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `LodyExtensionCapabilities` — the `_meta.lody` value under
/// `agentCapabilities`. Absent features are simply not advertised; `to_json`
/// emits only the present feature keys, in upstream declaration order.
pub(all) struct LodyExtensionCapabilities {
usage : LodyVersionOneCapability?
rate_limits : LodyRateLimitsCapability?
fork_at_turn : LodyVersionOneCapability?
steering : LodySteeringCapability?
tasks : LodyTaskCapability?
subagents : LodySubagentCapability?
goal : LodyGoalCapability?
compaction : LodyVersionOneCapability?
session_history : LodyVersionOneCapability?
} derive(Eq, Debug)
///|
pub fn LodyExtensionCapabilities::empty() -> LodyExtensionCapabilities {
LodyExtensionCapabilities::{
usage: None,
rate_limits: None,
fork_at_turn: None,
steering: None,
tasks: None,
subagents: None,
goal: None,
compaction: None,
session_history: None,
}
}
///|
pub fn LodyExtensionCapabilities::to_json(
self : LodyExtensionCapabilities,
) -> Json {
let pairs : Array[(String, Json)] = []
match self.usage {
Some(v) => pairs.push(("usage", v.to_json()))
None => ()
}
match self.rate_limits {
Some(v) => pairs.push(("rateLimits", v.to_json()))
None => ()
}
match self.fork_at_turn {
Some(v) => pairs.push(("forkAtTurn", v.to_json()))
None => ()
}
match self.steering {
Some(v) => pairs.push(("steering", v.to_json()))
None => ()
}
match self.tasks {
Some(v) => pairs.push(("tasks", v.to_json()))
None => ()
}
match self.subagents {
Some(v) => pairs.push(("subagents", v.to_json()))
None => ()
}
match self.goal {
Some(v) => pairs.push(("goal", v.to_json()))
None => ()
}
match self.compaction {
Some(v) => pairs.push(("compaction", v.to_json()))
None => ()
}
match self.session_history {
Some(v) => pairs.push(("sessionHistory", v.to_json()))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn LodyExtensionCapabilities::from_json(
raw : Json,
) -> Result[LodyExtensionCapabilities, String] {
try {
let ctx = "lody.capabilities"
let fields = object_fields(raw, ctx)
Ok(LodyExtensionCapabilities::{
usage: opt_sub(fields, ctx, "usage", LodyVersionOneCapability::from_json),
rate_limits: opt_sub(
fields,
ctx,
"rateLimits",
LodyRateLimitsCapability::from_json,
),
fork_at_turn: opt_sub(
fields,
ctx,
"forkAtTurn",
LodyVersionOneCapability::from_json,
),
steering: opt_sub(
fields,
ctx,
"steering",
LodySteeringCapability::from_json,
),
tasks: opt_sub(fields, ctx, "tasks", LodyTaskCapability::from_json),
subagents: opt_sub(
fields,
ctx,
"subagents",
LodySubagentCapability::from_json,
),
goal: opt_sub(fields, ctx, "goal", LodyGoalCapability::from_json),
compaction: opt_sub(
fields,
ctx,
"compaction",
LodyVersionOneCapability::from_json,
),
session_history: opt_sub(
fields,
ctx,
"sessionHistory",
LodyVersionOneCapability::from_json,
),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}