Skip to content

Rust SDK: add typed per-session capability controls#1455

Draft
Morabbin wants to merge 4 commits into
github:mainfrom
Morabbin:morabbin/rust-typed-session-capabilities
Draft

Rust SDK: add typed per-session capability controls#1455
Morabbin wants to merge 4 commits into
github:mainfrom
Morabbin:morabbin/rust-typed-session-capabilities

Conversation

@Morabbin

@Morabbin Morabbin commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds typed SessionConfig / ResumeSessionConfig fields and builder methods backed by the generated SessionCapability enum, so callers can express per-session capability opt-in / opt-out without stringly-typed flags.

This is a per-session API: the capability fields are sent as JSON-RPC wire parameters on session.create and session.resume, so it works for every transport including Transport::External.

Experimental. The new capability enable/disable surface is part of an experimental wire-protocol API. The Rust SDK marks the new fields and builders with the repository's <div class="warning">**Experimental.**</div> rustdoc block (the convention used in rust/src/generated/); there is no #[experimental] attribute, so the marker is documentation-only.

Why

Some SDK consumers use Transport::External, so spawn-time CLI flags have no effect. A per-session wire API is the correct approach for session-scoped runtime capabilities.

What

SessionCapability enum

  • Reuses the generated protocol enum and re-exports it from the crate root as github_copilot_sdk::SessionCapability.
  • Includes generated typed variants such as Memory, PlanMode, CanvasRenderer, Elicitation, McpApps, SessionStore, TuiHints, CliDocumentation, AskUser, InteractiveMode, and SystemNotifications.
  • Preserves generated per-variant rustdoc and serde wire names.
  • Rejects SessionCapability::Unknown as invalid outbound create/resume configuration, since that variant is only a deserialization fallback.

SessionConfig and ResumeSessionConfig (rust/src/types.rs)

New fields:

  • enabled_capabilities: Vec<SessionCapability> -- opt this session into additional capabilities.
  • disabled_capabilities: Vec<SessionCapability> -- opt this session out of capabilities; disable wins over enable on overlap.

Four builders on each config type:

  • with_enable_capability, with_disable_capability
  • with_enabled_capabilities, with_disabled_capabilities

Wire serialization (rust/src/wire.rs)

SessionCreateWire and SessionResumeWire gain:

  • enabledCapabilities?: SessionCapability[]
  • disabledCapabilities?: SessionCapability[]

Both fields are omitted from the wire when empty. The generated enum serde emits the protocol strings such as memory, plan-mode, and canvas-renderer.

Runtime dependency

Requires a runtime version that supports enabledCapabilities and disabledCapabilities. On older runtimes the fields are silently ignored.

Validation

  • cargo +nightly fmt --check
  • cargo clippy --lib --tests -- -D warnings
  • cargo test --lib (154 passed)
  • cargo test --doc (20 passed, 30 ignored)
  • cargo build

Copilot AI review requested due to automatic review settings May 27, 2026 14:47
@Morabbin Morabbin requested a review from a team as a code owner May 27, 2026 14:47
@Morabbin Morabbin marked this pull request as draft May 27, 2026 15:06
@Morabbin Morabbin changed the title rust: add typed SessionCapability enum and ClientOptions builders Rust SDK: add typed SessionCapability enum and ClientOptions builders May 27, 2026
@Morabbin Morabbin changed the title Rust SDK: add typed SessionCapability enum and ClientOptions builders Rust SDK: add typed per-session capability controls May 27, 2026
@Morabbin Morabbin force-pushed the morabbin/rust-typed-session-capabilities branch 6 times, most recently from 8899958 to cb93071 Compare June 3, 2026 11:48
@Morabbin Morabbin force-pushed the morabbin/rust-typed-session-capabilities branch from cb93071 to e59f4d0 Compare June 8, 2026 11:01
Adds a typed `SessionCapability` enum and matching `SessionConfig` /
`ResumeSessionConfig` fields plus builder methods, so callers can express
"enable memory", "disable plan-mode", etc. as a per-session wire parameter
rather than a spawn-time CLI flag.

- `SessionCapability` is `#[non_exhaustive]`, kebab-case-serialized (via
  `Display` / `FromStr` / `From<&str>` / `From<String>`), and carries an
  `Other(String)` escape hatch for forward compatibility with capabilities
  the runtime adds without requiring an SDK rebuild.
- `SessionConfig` and `ResumeSessionConfig` each gain
  `enabled_capabilities` / `disabled_capabilities` vectors and four
  builders: `with_enable_capability`, `with_disable_capability`,
  `with_enabled_capabilities`, `with_disabled_capabilities`.
- `SessionConfig::into_wire` and `ResumeSessionConfig::into_wire` convert
  the vecs to `Option<Vec<String>>` and emit them as
  `enabledCapabilities` / `disabledCapabilities` in the `session.create`
  and `session.resume` JSON-RPC payloads. Empty vecs are serialised as
  `None` (field omitted). Disable wins over enable on conflict (the runtime
  applies enable first, then disable).
- Works for every transport -- including `Transport::External` (Desktop app
  / shared CLI server) -- because it does not rely on CLI spawn arguments.

Pairs with github/copilot-agent-runtime#8918 (per-session capability API)
and github/agents#981 (Desktop missing memory capability).

10 new unit tests: 3 enum-level tests (Display / FromStr / From conversions)
and 7 wire-serialisation tests in a dedicated `capability_tests` module in
`types.rs` (empty omitted, single enable, single disable, bulk-replace,
Other round-trip, resume empty, resume enable+disable).

Pre-existing test breakage: rust/tests/session_test.rs and
rust/tests/protocol_version_test.rs reference removed API methods on main
and are unrelated to this change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Morabbin Morabbin force-pushed the morabbin/rust-typed-session-capabilities branch from e59f4d0 to e205d4c Compare June 9, 2026 07:20
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread rust/README.md Outdated
> [github/copilot-agent-runtime#8918](https://github.com/github/copilot-agent-runtime/pull/8918)
> or later. On older runtimes the fields are silently ignored.
> Pairs with [github/agents#1081](https://github.com/github/agents/issues/1081)
> (Desktop app missing memory capability).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid referring to closed-source repos anywhere in the open-source code.

@Morabbin Morabbin Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang it! Will excise, apologies.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replying on Morabbin's behalf: fixed in the latest pushes. The README/source docs and PR body no longer add closed-source repository references.

Comment thread rust/src/lib.rs Outdated
/// SDK release can still be opted into without waiting for a new
/// enum variant.
///
/// Requires github/copilot-agent-runtime#8918 or later.

@SteveSandersonMS SteveSandersonMS Jun 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid referring to closed source. There are a few comments like this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix incoming; removing all mentions from all parts of the PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replying on Morabbin's behalf: fixed in the latest pushes. The README/source docs and PR body no longer add closed-source repository references.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread rust/src/lib.rs Outdated
///
/// Pass any kebab-case capability string here to forward it
/// verbatim to the runtime.
Other(String),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than duplicating the list of capabilities, could we just directly use crate::generated::api_types::SessionCapability in the API? That would mean it automatically brings forwards the annotations for individual entries being experimental, plus avoids having to continually maintain this code whenever the set of capabilities changes.

I know that won't have an equivalent to Other(string) but the SDK requires a matching runtime version, so in general we don't need to provide forward compatibility for this situation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally we plan soon to change session.create/session.resume to work via codegen instead of being hand-authored. At that point the set of capabilities would have to be a regular enum just like all the other enums we reference from those options (unless we also implement some nontrivial codegen changes across 6 languages).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me; change incoming

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replying on Morabbin's behalf: updated this to use the generated SessionCapability enum directly, re-exported from the crate root. The custom duplicated enum, Other(String), string conversions, and manual string serde are gone.

The create/resume config now stores generated SessionCapability values and the wire structs serialize those enum values directly. I also added coverage that SessionCapability::CanvasRenderer serializes to canvas-renderer, and reject SessionCapability::Unknown as invalid outbound config since it is only the generated deserialization fallback. This should line up with the planned generated create/resume path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread rust/src/types.rs
where
I: IntoIterator<Item = SessionCapability>,
{
self.enabled_capabilities = capabilities.into_iter().collect();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since with_enable_capability appends an item, I would have expected with_enable_capabilities also to append items. It seems surprising that it would also delete any existing items.

Comment thread rust/README.md
- `enabledCapabilities` -- capabilities to opt the session into (extends the `SDK_CAPABILITIES` baseline)
- `disabledCapabilities` -- capabilities to opt the session out of (disable wins on overlap)

This approach works for every transport -- including `Transport::External` -- because it does not rely on CLI spawn arguments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an implementation detail. Let's only document things that are relevant to SDK consumers.

Comment thread rust/README.md
| `SessionStore` | `session-store` | Cross-session history tools and session-store metadata |
| `McpApps` | `mcp-apps` | MCP-Apps `ui://` resource passthrough (SEP-1865) |
| `CanvasRenderer` | `canvas-renderer` | Host-rendered extension canvases |
| `Unknown` | *(none)* | Deserialization fallback; rejected for outbound config |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably best not to list the full set in the docs, because then we have to keep updating the docs (or by default we don't, and the docs get stale). The enum is already self-documenting.

Comment thread rust/README.md
none of them are scheduled for removal.

- **`SessionCapability` enum** -- generated typed enum for per-session
capability opt-in / opt-out. Sent via `enabledCapabilities` /

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't document whether things are generated or not - that's an implementation detail and isn't relevant to SDK consumers.

Comment thread rust/README.md
calls -- works for all transports including `Transport::External`. See
[Session capabilities](#session-capabilities) above. Marked
**experimental** via the repository's `<div class="warning">` rustdoc
convention. Node/Python/Go/.NET accept stringly-typed flags.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node/Python/Go/.NET accept stringly-typed flags.

Is that true? Even if so there's no reason for the Rust docs to discuss that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants