Skip to main content
See the spec’s Session Config Options page for the protocol rules; this page covers the Java types and the decisions the spec leaves open.

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 through AcpSchema:
  • SessionConfigSelect: a choice from a fixed set of options.
  • SessionConfigBoolean: an on/off switch.
Build a model picker with the dedicated factory:
For anything else, use the builders:
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 on NewSessionResponse, LoadSessionResponse, and ResumeSessionResponse:
Boolean options are stable, but only send one to a client that advertised support for them (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 calls setSessionConfigOption; the agent’s handler returns the complete new list, not a delta:
The builder form is the same handler under a different name: .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):
The same applies to a boolean option set by a client that never advertised boolean support: treat the ID as unknown and answer -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:
The spec is silent on whether the agent should also send an update after a client-initiated change. Since SetSessionConfigOptionResponse already carries the complete new state, don’t send a redundant ConfigOptionUpdate for that case.

Relationship to session modes

Config options supersede session/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.

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