Skip to content

Commit 912c0a7

Browse files
fscarponibenbrandt
andauthored
feat(unstable): Add config option type for boolean on/off toggles (#576)
* Add flag config option type for boolean on/off toggles * Update to make this less breaking --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
1 parent 2419e54 commit 912c0a7

5 files changed

Lines changed: 575 additions & 37 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ unstable = [
2525
"unstable_session_stop",
2626
"unstable_session_usage",
2727
"unstable_message_id",
28+
"unstable_boolean_config",
2829
]
2930
unstable_auth_methods = []
3031
unstable_cancel_request = []
@@ -36,6 +37,7 @@ unstable_session_resume = []
3637
unstable_session_stop = []
3738
unstable_session_usage = []
3839
unstable_message_id = []
40+
unstable_boolean_config = []
3941

4042
[[bin]]
4143
name = "generate"

docs/protocol/draft/schema.mdx

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -726,26 +726,41 @@ Sets the current value for a session configuration option.
726726

727727
Request parameters for setting a session configuration option.
728728

729-
**Type:** Object
730-
731-
**Properties:**
729+
**Type:** Union
732730

733-
<ResponseField name="_meta" type={"object | null"} >
734-
The _meta property is reserved by ACP to allow clients and agents to attach additional
735-
metadata to their interactions. Implementations MUST NOT make assumptions about values at
736-
these keys.
731+
<ResponseField name="boolean" type="object">
732+
A boolean value (`type: "boolean"`).
737733

738-
See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
734+
<Expandable title="Properties">
739735

736+
<ResponseField name="type" type={"string"} required>
737+
The discriminator value. Must be `"boolean"`.
740738
</ResponseField>
741-
<ResponseField name="configId" type={<a href="#sessionconfigid">SessionConfigId</a>} required>
742-
The ID of the configuration option to set.
739+
<ResponseField name="value" type={"boolean"} required>
740+
The boolean value.
743741
</ResponseField>
744-
<ResponseField name="sessionId" type={<a href="#sessionid">SessionId</a>} required>
745-
The ID of the session to set the configuration option for.
742+
743+
</Expandable>
746744
</ResponseField>
747-
<ResponseField name="value" type={<a href="#sessionconfigvalueid">SessionConfigValueId</a>} required>
748-
The ID of the configuration option value to set.
745+
746+
<ResponseField name="Object" type="object">
747+
A `SessionConfigValueId` string value.
748+
749+
This is the default when `type` is absent on the wire. Unknown `type`
750+
values with string payloads also gracefully deserialize into this
751+
variant.
752+
753+
<Expandable title="Properties">
754+
755+
<ResponseField
756+
name="value"
757+
type={<a href="#sessionconfigvalueid">SessionConfigValueId</a>}
758+
required
759+
>
760+
The value ID.
761+
</ResponseField>
762+
763+
</Expandable>
749764
</ResponseField>
750765

751766
#### <span class="font-mono">SetSessionConfigOptionResponse</span>
@@ -3381,6 +3396,22 @@ Whether the agent supports `session/stop`.
33813396

33823397
</ResponseField>
33833398

3399+
## <span class="font-mono">SessionConfigBoolean</span>
3400+
3401+
**UNSTABLE**
3402+
3403+
This capability is not part of the spec yet, and may be removed or changed at any point.
3404+
3405+
A boolean on/off toggle session configuration option payload.
3406+
3407+
**Type:** Object
3408+
3409+
**Properties:**
3410+
3411+
<ResponseField name="currentValue" type={"boolean"} required>
3412+
The current value of the boolean option.
3413+
</ResponseField>
3414+
33843415
## <span class="font-mono">SessionConfigGroupId</span>
33853416

33863417
Unique identifier for a session configuration option value group.
@@ -3397,11 +3428,12 @@ Unique identifier for a session configuration option.
33973428

33983429
A session configuration option selector and its current state.
33993430

3400-
Single-value selector (dropdown).
3431+
**Type:** Union
34013432

3402-
**Type:** Object
3433+
<ResponseField name="select" type="object">
3434+
Single-value selector (dropdown).
34033435

3404-
**Properties:**
3436+
<Expandable title="Properties">
34053437

34063438
<ResponseField
34073439
name="currentValue"
@@ -3417,6 +3449,31 @@ Single-value selector (dropdown).
34173449
>
34183450
The set of selectable options.
34193451
</ResponseField>
3452+
<ResponseField name="type" type={"string"} required>
3453+
The discriminator value. Must be `"select"`.
3454+
</ResponseField>
3455+
3456+
</Expandable>
3457+
</ResponseField>
3458+
3459+
<ResponseField name="boolean" type="object">
3460+
**UNSTABLE**
3461+
3462+
This capability is not part of the spec yet, and may be removed or changed at any point.
3463+
3464+
Boolean on/off toggle.
3465+
3466+
<Expandable title="Properties">
3467+
3468+
<ResponseField name="currentValue" type={"boolean"} required>
3469+
The current value of the boolean option.
3470+
</ResponseField>
3471+
<ResponseField name="type" type={"string"} required>
3472+
The discriminator value. Must be `"boolean"`.
3473+
</ResponseField>
3474+
3475+
</Expandable>
3476+
</ResponseField>
34203477

34213478
## <span class="font-mono">SessionConfigOptionCategory</span>
34223479

docs/rfds/boolean-config-option.mdx

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ However, there is no native way to represent a simple boolean on/off toggle. To
1919

2020
- Add a `SessionConfigBoolean` struct with a `current_value: bool` field
2121
- Add a `Boolean(SessionConfigBoolean)` variant to the `SessionConfigKind` enum, discriminated by `"type": "boolean"`
22-
- Add a `SessionConfigOptionValue` enum (untagged: `String` | `Bool`) so that `SetSessionConfigOptionRequest.value` can accept both string values (for `select`) and boolean values (for `flag`)
22+
- Add a `SessionConfigOptionValue` internally-tagged enum so that `SetSessionConfigOptionRequest` can carry both string values (for `select`) and boolean values (for `boolean`) with an explicit `type` discriminator
2323
- Provide convenience constructors and `From` impls for ergonomic usage
2424
- Update documentation and regenerate schema files
2525

@@ -65,7 +65,9 @@ In a `session/new` response (or any response containing `configOptions`):
6565

6666
### Wire format: setting a boolean option
6767

68-
The `session/set_config_option` request uses a string value, consistent with `select` options:
68+
The `session/set_config_option` request carries a `type` discriminator alongside the `value`. The `type` field describes the _shape_ of the value, not the option kind.
69+
70+
When `type` is absent the value is treated as a `SessionConfigValueId` string, preserving backwards compatibility with existing clients:
6971

7072
```json
7173
{
@@ -75,11 +77,27 @@ The `session/set_config_option` request uses a string value, consistent with `se
7577
"params": {
7678
"sessionId": "sess_abc123",
7779
"configId": "brave_mode",
80+
"type": "boolean",
7881
"value": true
7982
}
8083
}
8184
```
8285

86+
For select options the `type` field can be omitted (defaults to `value_id`):
87+
88+
```json
89+
{
90+
"jsonrpc": "2.0",
91+
"id": 3,
92+
"method": "session/set_config_option",
93+
"params": {
94+
"sessionId": "sess_abc123",
95+
"configId": "mode",
96+
"value": "code"
97+
}
98+
}
99+
```
100+
83101
The response returns the full set of config options with current values, as with `select`:
84102

85103
```json
@@ -108,15 +126,17 @@ The response returns the full set of config options with current values, as with
108126
}
109127
```
110128

111-
A working implementation is available at: https://github.com/fscarponi/agent-client-protocol/tree/fabrizio.scarponi/flag-config-option
112-
113129
Key changes:
114130

115-
1. `SessionConfigFlag` struct with `current_value: bool`
116-
2. `Flag` variant in `SessionConfigKind` (tagged via `"type": "flag"`)
117-
3. `SessionConfigOptionValue` untagged enum (`String` | `Bool`) replacing `SessionConfigValueId` in `SetSessionConfigOptionRequest.value`
118-
4. `From` impls ensure backward compatibility — existing code passing strings still compiles
119-
5. Wire-level backward compatible: existing JSON payloads with string values remain valid
131+
1. `SessionConfigBoolean` struct with `current_value: bool`
132+
2. `Boolean(SessionConfigBoolean)` variant in `SessionConfigKind` (tagged via `"type": "boolean"`)
133+
3. `SessionConfigOptionValue` enum using `#[serde(tag = "type")]` with a `#[serde(untagged)]` fallback variant — the same pattern as `AuthMethod`:
134+
- `Boolean { value: bool }` — matched when `type` is `"boolean"`
135+
- `ValueId { value: SessionConfigValueId }` — untagged fallback when `type` is absent or unrecognised
136+
4. `SessionConfigOptionValue` is flattened (`#[serde(flatten)]`) onto `SetSessionConfigOptionRequest`, producing top-level `type` and `value` fields on the wire
137+
5. The `value` field type change in `SetSessionConfigOptionRequest` is gated behind `#[cfg(feature = "unstable_boolean_config")]` — without the feature the field remains `SessionConfigValueId`
138+
6. `From` impls (`&str`, `SessionConfigValueId`, `bool`) ensure ergonomic construction
139+
7. Wire-level backward compatible: existing JSON payloads without a `type` field remain valid via the untagged fallback
120140

121141
### Client capabilities
122142

@@ -126,12 +146,13 @@ Per the existing protocol design, clients that receive a config option with an u
126146

127147
### What alternative approaches did you consider, and why did you settle on this one?
128148

129-
We considered reusing the existing `select` type with a convention (e.g., options named "on"/"off"), but this would require clients to implement non-agnostic detection logic, which contradicts the goal of a standardized protocol. A dedicated `flag` type is cleaner and lets clients render the appropriate UI control without guessing.
149+
We considered reusing the existing `select` type with a convention (e.g., options named "on"/"off"), but this would require clients to implement non-agnostic detection logic, which contradicts the goal of a standardized protocol. A dedicated `boolean` type is cleaner and lets clients render the appropriate UI control without guessing.
130150

131151
### Is this a breaking change?
132152

133-
On the wire/JSON level: no. `SessionConfigOptionValue` uses `#[serde(untagged)]`, so existing string payloads deserialize correctly. On the Rust API level: the type of `SetSessionConfigOptionRequest.value` changed, but `From` impls ensure source compatibility for users of the `new()` constructor.
153+
On the wire/JSON level: no. When `type` is absent the value is treated as a `SessionConfigValueId`, so existing payloads deserialize correctly. On the Rust API level: the type of `SetSessionConfigOptionRequest.value` changes, but this is gated behind `unstable_boolean_config`. Without the feature flag the stable API is unchanged. With the feature flag, `From` impls ensure source compatibility for users of the `new()` constructor.
134154

135155
## Revision history
136156

137157
- 2026-02-24: Initial proposal
158+
- 2026-03-05: Updated to reflect final implementation — `flag` renamed to `boolean`, value type changed from untagged `String | Bool` enum to internally-tagged enum with `type` discriminator and untagged `ValueId` fallback, feature-gated behind `unstable_boolean_config`

schema/schema.unstable.json

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2882,6 +2882,17 @@
28822882
},
28832883
"type": "object"
28842884
},
2885+
"SessionConfigBoolean": {
2886+
"description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA boolean on/off toggle session configuration option payload.",
2887+
"properties": {
2888+
"currentValue": {
2889+
"description": "The current value of the boolean option.",
2890+
"type": "boolean"
2891+
}
2892+
},
2893+
"required": ["currentValue"],
2894+
"type": "object"
2895+
},
28852896
"SessionConfigGroupId": {
28862897
"description": "Unique identifier for a session configuration option value group.",
28872898
"type": "string"
@@ -2911,6 +2922,22 @@
29112922
},
29122923
"required": ["type"],
29132924
"type": "object"
2925+
},
2926+
{
2927+
"allOf": [
2928+
{
2929+
"$ref": "#/$defs/SessionConfigBoolean"
2930+
}
2931+
],
2932+
"description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nBoolean on/off toggle.",
2933+
"properties": {
2934+
"type": {
2935+
"const": "boolean",
2936+
"type": "string"
2937+
}
2938+
},
2939+
"required": ["type"],
2940+
"type": "object"
29142941
}
29152942
],
29162943
"properties": {
@@ -3475,6 +3502,39 @@
34753502
]
34763503
},
34773504
"SetSessionConfigOptionRequest": {
3505+
"anyOf": [
3506+
{
3507+
"description": "A boolean value (`type: \"boolean\"`).",
3508+
"properties": {
3509+
"type": {
3510+
"const": "boolean",
3511+
"type": "string"
3512+
},
3513+
"value": {
3514+
"description": "The boolean value.",
3515+
"type": "boolean"
3516+
}
3517+
},
3518+
"required": ["type", "value"],
3519+
"type": "object"
3520+
},
3521+
{
3522+
"description": "A [`SessionConfigValueId`] string value.\n\nThis is the default when `type` is absent on the wire. Unknown `type`\nvalues with string payloads also gracefully deserialize into this\nvariant.",
3523+
"properties": {
3524+
"value": {
3525+
"allOf": [
3526+
{
3527+
"$ref": "#/$defs/SessionConfigValueId"
3528+
}
3529+
],
3530+
"description": "The value ID."
3531+
}
3532+
},
3533+
"required": ["value"],
3534+
"title": "value_id",
3535+
"type": "object"
3536+
}
3537+
],
34783538
"description": "Request parameters for setting a session configuration option.",
34793539
"properties": {
34803540
"_meta": {
@@ -3497,17 +3557,9 @@
34973557
}
34983558
],
34993559
"description": "The ID of the session to set the configuration option for."
3500-
},
3501-
"value": {
3502-
"allOf": [
3503-
{
3504-
"$ref": "#/$defs/SessionConfigValueId"
3505-
}
3506-
],
3507-
"description": "The ID of the configuration option value to set."
35083560
}
35093561
},
3510-
"required": ["sessionId", "configId", "value"],
3562+
"required": ["sessionId", "configId"],
35113563
"type": "object",
35123564
"x-method": "session/set_config_option",
35133565
"x-side": "agent"

0 commit comments

Comments
 (0)