Why this replaced session/set_model
A dedicated model-selection method turned out to be too narrow: agents wanted selectors for
reasoning effort, variants, and other settings too, and each new hard-coded method would leave the
protocol carrying methods nobody uses once agents move past them. So ACP lets an agent declare its
own selectors, each with an ID and an optional semantic category, and model choice becomes just one
selector with category: "model". session/set_model, SetSessionModelRequest/Response,
SessionModelState, ModelInfo, and @SetSessionModel are removed entirely in 0.80.0; see the
migration guide if you’re upgrading.
The types
A config option is one of two kinds, both exposed throughAcpSchema:
SessionConfigSelect: a choice from a fixed set of options.SessionConfigBoolean: an on/off switch.
build() throws IllegalStateException naming the first missing required field, and, for a select,
when the options (across every group) are empty or currentValue isn’t the value of one of them: an
option no client could display correctly. options() on a
select can be flat (List<SessionConfigSelectOption>) or grouped
(List<SessionConfigSelectGroup>); SessionConfigSelectOptions.allOptions() flattens either shape,
which is what most code should call rather than branching on UngroupedSelectOptions vs
GroupedSelectOptions directly.
AcpSchema.SessionConfigOptionCategory holds the categories the protocol reserves, as plain
String constants: MODE, MODEL, MODEL_CONFIG, THOUGHT_LEVEL. category is a free string,
not a closed enum: a custom category is allowed as long as it starts with _, and clients must
tolerate a missing or unrecognized one. In Java, always write the reserved categories through the
SessionConfigOptionCategory constants rather than string literals.
Advertising config options
The agent lists the full set onNewSessionResponse, LoadSessionResponse, and
ResumeSessionResponse:
clientCapabilities.session.configOptions.boolean, spelled in Java as
ClientSessionCapabilities.withBooleanConfigOptions()). The SDK does not filter this for you:
check the connection’s NegotiatedCapabilities.supportsBooleanConfigOptions() yourself before
including a boolean option.
Changing an option
The client callssetSessionConfigOption; the agent’s handler returns the complete new list,
not a delta:
.setSessionConfigOptionHandler(req -> new SetSessionConfigOptionResponse(fullOptionsList)).
req.value() is untyped (Object): a String for a select, a Boolean for a boolean.
req.type() is null for a select and "boolean" for a boolean, so dispatch on req.configId()
and check with instanceof rather than trusting type() to disambiguate. The SDK validates none of
this: a bad option ID, a value not on offer, or a value of the wrong type all reach the handler as
sent. The spec defines no error for these cases either; the natural answer, and what this page
recommends, is -32602 (Invalid params):
-32602, the same as any option you didn’t offer that client.
Typed parameters instead of req.value()
An annotated @SetSessionConfigOption method can take @ConfigId String and @ConfigValue
directly, instead of pulling the id and value out of the request:
@ConfigValue reads as whichever type the parameter declares: String for a select’s value id,
boolean/Boolean for a boolean option, or Object to accept either kind and branch yourself. A
value of the wrong kind for the parameter’s declared type answers -32602 before the method is
called, so the req.value() instanceof String type-check boilerplate disappears for the common
case; whether the id and value actually name an option (and a value) the session offers is still the
method’s own job, same as with the raw request.
When the agent sends ConfigOptionUpdate
Send a ConfigOptionUpdate session update when the agent itself changes an option, for example
switching a mode after planning, falling back to a different model after a rate limit, or exposing
an option that depends on discovered context. It always carries the full, current list:
SetSessionConfigOptionResponse already carries the complete new state, don’t send a
redundant ConfigOptionUpdate for that case.
Relationship to session modes
Config options supersedesession/set_mode, but not yet: the spec says modes will be removed in a
future protocol version, and during the transition an agent with mode-like settings should send
both a category: "mode" config option and the separate modes field, while a client that
supports config options should prefer them and ignore modes. session/set_mode stays in the SDK
for now; don’t remove it just because config options exist.
Related
Concepts
Capabilities, sessions, and the rest of the vocabulary this page assumes
Migration Guide
Every breaking change from 0.18.0, including the full session/set_model removal