diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1bf181eb..d39423fb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,29 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + msrv: + name: Minimum supported Rust version + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Read MSRV from Cargo.toml + id: msrv + run: | + msrv="$(sed -n 's/^rust-version[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' Cargo.toml)" + test -n "$msrv" + echo "version=$msrv" >> "$GITHUB_OUTPUT" + + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 + with: + toolchain: ${{ steps.msrv.outputs.version }} + + - name: Check with MSRV + run: cargo check --all-targets --all-features --locked + build: name: Build runs-on: ubuntu-latest @@ -32,7 +55,7 @@ jobs: cache: "npm" - name: Setup Rust - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 + uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 with: toolchain: nightly,stable components: rustfmt,clippy @@ -44,7 +67,7 @@ jobs: run: npm run format:check - name: Check for typos - uses: crate-ci/typos@7c572958218557a3272c2d6719629443b5cc26fd + uses: crate-ci/typos@aca895bf05aec0cb7dffa6f94495e923224d9f17 with: config: ./typos.toml @@ -61,3 +84,70 @@ jobs: run: | npm run generate git diff --exit-code || (echo "Generated files are out of date. Run 'npm run generate' and commit the changes." && exit 1) + + rust-changes: + name: Detect Rust changes + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.rust-changes.outputs.changed }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + persist-credentials: false + + - name: Check for Rust file changes + id: rust-changes + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }} + HEAD_SHA: ${{ github.sha }} + run: | + if [ "$EVENT_NAME" = "workflow_dispatch" ]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then + echo "changed=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + + if git diff --name-only "$BASE_SHA" "$HEAD_SHA" | grep -Eq '(^|/)(Cargo\.toml|Cargo\.lock)$|\.rs$'; then + echo "changed=true" >> "$GITHUB_OUTPUT" + else + echo "changed=false" >> "$GITHUB_OUTPUT" + fi + + feature-powerset: + name: Feature powerset (${{ matrix.partition }}) + needs: rust-changes + if: needs.rust-changes.outputs.changed == 'true' + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + partition: ["1/4", "2/4", "3/4", "4/4"] + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 + with: + toolchain: stable + + - name: Install cargo-hack + uses: taiki-e/install-action@b550161ef8a7bc4f2a671c0b03a18ac9ccedea1e + with: + tool: cargo-hack + + - name: Check feature powerset + # `unstable` is an aggregate alias for the individual unstable_* features, + # so excluding it avoids duplicate combinations. Limit the powerset to + # feature pairs to keep CI practical; the regular CI all-features build + # still covers the all-on case. + run: cargo hack --locked check --feature-powerset --exclude-features unstable --no-dev-deps --depth 2 --partition ${{ matrix.partition }} diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml index 915e8d838..0542cf2cb 100644 --- a/.github/workflows/release-plz.yml +++ b/.github/workflows/release-plz.yml @@ -30,7 +30,7 @@ jobs: # Generating a GitHub token, so that PRs and tags created by # the release-plz-action can trigger actions workflows. name: Generate GitHub token - uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 id: generate-token with: # GitHub App ID secret name @@ -38,7 +38,7 @@ jobs: # GitHub App private key secret name private-key: ${{ secrets.RELEASE_PLZ_APP_PRIVATE_KEY }} - name: Run release-plz - uses: release-plz/action@1528104d2ca23787631a1c1f022abb64b34c1e11 + uses: release-plz/action@064f4d1e36c843611ddf013be726beaa4ad804db with: command: release env: @@ -59,7 +59,7 @@ jobs: - *install-rust - *generate-token - name: Run release-plz - uses: release-plz/action@1528104d2ca23787631a1c1f022abb64b34c1e11 + uses: release-plz/action@064f4d1e36c843611ddf013be726beaa4ad804db with: command: release-pr env: diff --git a/.github/workflows/sync-registry.yml b/.github/workflows/sync-registry.yml index d9e0f44ee..c83c22f47 100644 --- a/.github/workflows/sync-registry.yml +++ b/.github/workflows/sync-registry.yml @@ -56,7 +56,7 @@ jobs: # Generating a GitHub token, so that PRs and tags created by # the action can trigger actions workflows. - name: Generate GitHub token - uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 id: generate-token with: # GitHub App ID secret name diff --git a/.gitignore b/.gitignore index fac65dd9e..5e93ca7d0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,8 @@ typescript/*.js.map # TypeDoc generated documentation typescript/docs/ + +.agents +.kiro +.claude + diff --git a/AGENTS.md b/AGENTS.md index e73cf0db7..51da2ca7e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,14 +47,14 @@ This is a **protocol schema library** (not a runtime application). There are no ### Key commands (see `package.json` scripts) -| Command | Purpose | -|---|---| -| `npm run check` | Full CI pipeline: clippy, format check, spellcheck, tests | -| `npm run generate` | Regenerate JSON schemas from Rust types + format | -| `cargo test --all-features` | Run Rust unit + doc tests | -| `cargo clippy --all-features` | Lint Rust code | -| `npm run format:check` | Verify Prettier + rustfmt formatting | -| `npm run format` | Auto-fix formatting | +| Command | Purpose | +| ----------------------------- | --------------------------------------------------------- | +| `npm run check` | Full CI pipeline: clippy, format check, spellcheck, tests | +| `npm run generate` | Regenerate JSON schemas from Rust types + format | +| `cargo test --all-features` | Run Rust unit + doc tests | +| `cargo clippy --all-features` | Lint Rust code | +| `npm run format:check` | Verify Prettier + rustfmt formatting | +| `npm run format` | Auto-fix formatting | ### Gotchas diff --git a/CHANGELOG.md b/CHANGELOG.md index daca8d04c..85af95d94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # Changelog +## [0.13.3](https://github.com/agentclientprotocol/agent-client-protocol/compare/v0.13.2...v0.13.3) - 2026-05-22 + +### Added + +- Stabilize logout method ([#1273](https://github.com/agentclientprotocol/agent-client-protocol/pull/1273)) + +### Fixed + +- *(unstable)* Rename provider method types to singular ([#1272](https://github.com/agentclientprotocol/agent-client-protocol/pull/1272)) + +### Other + +- *(rfd)* Move additional directories RFD to Preview ([#1276](https://github.com/agentclientprotocol/agent-client-protocol/pull/1276)) +- Add schema download note to schema page ([#1269](https://github.com/agentclientprotocol/agent-client-protocol/pull/1269)) +- *(deps)* bump num-conv from 0.2.1 to 0.2.2 in the minor group ([#1244](https://github.com/agentclientprotocol/agent-client-protocol/pull/1244)) +- Set minimum supported Rust version ([#1232](https://github.com/agentclientprotocol/agent-client-protocol/pull/1232)) +- Document ACP versioning semantics ([#1229](https://github.com/agentclientprotocol/agent-client-protocol/pull/1229)) + +## [0.13.2](https://github.com/agentclientprotocol/agent-client-protocol/compare/v0.13.1...v0.13.2) - 2026-05-17 + +### Fixed + +- *(unstable)* Update additionalDirectories guidance ([#1227](https://github.com/agentclientprotocol/agent-client-protocol/pull/1227)) + +## [0.13.1](https://github.com/agentclientprotocol/agent-client-protocol/compare/v0.13.0...v0.13.1) - 2026-05-16 + +### Added + +- *(unstable)* Add unstable session delete support ([#1216](https://github.com/agentclientprotocol/agent-client-protocol/pull/1216)) + +## [0.13.0](https://github.com/agentclientprotocol/agent-client-protocol/compare/v0.12.2...v0.13.0) - 2026-05-12 + +### Added + +- *(unstable)* Add experimental MCP-over-ACP message types ([#1185](https://github.com/agentclientprotocol/agent-client-protocol/pull/1185)) + +### Other + +- add unstable mcp-over-acp additions to the schema ([#1173](https://github.com/agentclientprotocol/agent-client-protocol/pull/1173)) +- *(deps)* bump the minor group with 3 updates ([#1178](https://github.com/agentclientprotocol/agent-client-protocol/pull/1178)) +- *(deps)* bump the minor group with 2 updates ([#1121](https://github.com/agentclientprotocol/agent-client-protocol/pull/1121)) +- *(unstable)* Start setting up v2 Schema scaffolding for experimentation ([#1099](https://github.com/agentclientprotocol/agent-client-protocol/pull/1099)) +- reorganize to v1 module ([#1094](https://github.com/agentclientprotocol/agent-client-protocol/pull/1094)) + ## [0.12.2](https://github.com/agentclientprotocol/agent-client-protocol/compare/v0.12.1...v0.12.2) - 2026-04-23 ### Added diff --git a/Cargo.lock b/Cargo.lock index 4eca15f51..5b6329599 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "agent-client-protocol-schema" -version = "0.12.2" +version = "0.13.3" dependencies = [ "anyhow", "derive_more", @@ -43,6 +43,15 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -51,9 +60,9 @@ checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "cc" -version = "1.2.61" +version = "1.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", "shlex", @@ -290,9 +299,9 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-traits" @@ -473,11 +482,12 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.18.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" dependencies = [ "base64", + "bs58", "chrono", "hex", "indexmap 1.9.3", @@ -492,9 +502,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.18.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" dependencies = [ "darling", "proc-macro2", @@ -577,6 +587,21 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tracing" version = "0.1.44" diff --git a/Cargo.toml b/Cargo.toml index 55ed3693c..1662ab600 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "agent-client-protocol-schema" authors = ["Zed "] -version = "0.12.2" +version = "0.13.3" edition = "2024" license = "Apache-2.0" description = "A protocol for standardizing communication between code editors and AI coding agents" @@ -12,6 +12,7 @@ readme = "README.md" keywords = ["agent", "client", "protocol", "ai", "editor"] categories = ["development-tools", "api-bindings"] include = ["/src/**/*.rs", "/README.md", "/LICENSE", "/Cargo.toml"] +rust-version = "1.88.0" [features] unstable = [ @@ -19,9 +20,10 @@ unstable = [ "unstable_cancel_request", "unstable_elicitation", "unstable_llm_providers", - "unstable_logout", + "unstable_mcp_over_acp", "unstable_nes", "unstable_session_additional_directories", + "unstable_session_delete", "unstable_session_fork", "unstable_session_model", "unstable_session_usage", @@ -37,9 +39,10 @@ unstable_auth_methods = [] unstable_cancel_request = [] unstable_elicitation = [] unstable_llm_providers = [] -unstable_logout = [] +unstable_mcp_over_acp = [] unstable_nes = [] unstable_session_additional_directories = [] +unstable_session_delete = [] unstable_session_fork = [] unstable_session_model = [] unstable_session_usage = [] @@ -61,7 +64,7 @@ derive_more = { version = "2", features = ["from", "display"] } schemars = { version = "1" } serde = { version = "1", features = ["derive", "rc"] } serde_json = { version = "1", features = ["raw_value"] } -serde_with = { version = "3.18.0", features = ["json", "schemars_1"] } +serde_with = { version = "3.20.0", features = ["json", "schemars_1"] } strum = { version = "0.28", features = ["derive"] } tracing = { version = "0.1", default-features = false, optional = true } diff --git a/README.md b/README.md index 7f60b301e..f27a8d100 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,18 @@ The Agent Client Protocol (ACP) standardizes communication between _code editors Learn more at [agentclientprotocol.com](https://agentclientprotocol.com/). +## Versioning + +The published crate and schema package versions describe the Rust crate and JSON Schema artifacts themselves. They follow the compatibility expectations of those artifacts: Rust APIs, generated schema structure, artifact layout, and other details that downstream SDKs or code generators may consume. + +**The current stable ACP protocol version is `1`.** + +ACP wire compatibility is determined separately by the protocol version exchanged during `initialize` via `protocolVersion`. The `version` field in `schema/meta*.json` also describes the ACP protocol version that the corresponding schema represents. + +This means two versions of the JSON Schema artifacts can describe the same wire-compatible ACP protocol version while having different schema structure for SDK generators. For example, a release might change how definitions are organized, named, or emitted in the JSON Schema in a way that affects downstream code generation without changing the JSON messages exchanged by ACP clients and agents. + +Consumers should not infer wire compatibility from the crate or schema package version alone. Use the negotiated `protocolVersion` to determine the ACP wire protocol shape and breaking-compatibility level. Within a protocol version, use the exchanged capabilities to decide which optional ACP messages and features are supported. Use artifact versions to manage compatibility with this repository's Rust and schema outputs. + ## Integrations - [Schema](./schema/schema.json) diff --git a/docs/announcements/logout-method-stabilized.mdx b/docs/announcements/logout-method-stabilized.mdx new file mode 100644 index 000000000..9ba6361d1 --- /dev/null +++ b/docs/announcements/logout-method-stabilized.mdx @@ -0,0 +1,13 @@ +--- +title: Logout Method is stabilized +sidebarTitle: Logout Method stabilized +description: Announcement that the logout method is now part of the stable ACP protocol. +--- + +**Published:** May 21, 2026 + +The [Logout Method RFD](/rfds/logout-method) has moved to Completed and the `logout` method is stabilized. + +When advertised via `agentCapabilities.auth.logout`, Clients can now ask Agents to end the current authenticated state and return the connection to a state where future authentication-gated requests require `authenticate` again. + +For the protocol documentation, see [Logging Out](/protocol/authentication#logging-out). diff --git a/docs/docs.json b/docs/docs.json index 84d717ec0..988e18433 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -64,6 +64,7 @@ "pages": [ "protocol/overview", "protocol/initialization", + "protocol/authentication", "protocol/session-setup", "protocol/session-list", "protocol/prompt-turn", @@ -82,10 +83,24 @@ "group": "Draft: In Progress and May Change", "hidden": true, "pages": [ + "protocol/draft/overview", + "protocol/draft/authentication", + "protocol/draft/initialization", "protocol/draft/session-setup", "protocol/draft/session-list", + "protocol/draft/session-delete", + "protocol/draft/prompt-turn", + "protocol/draft/content", + "protocol/draft/tool-calls", "protocol/draft/file-system", "protocol/draft/cancellation", + "protocol/draft/terminals", + "protocol/draft/agent-plan", + "protocol/draft/session-modes", + "protocol/draft/session-config-options", + "protocol/draft/slash-commands", + "protocol/draft/extensibility", + "protocol/draft/transports", "protocol/draft/schema" ] } @@ -120,22 +135,28 @@ "rfds/mcp-over-acp", "rfds/session-usage", "rfds/auth-methods", - "rfds/rust-sdk-v1", - "rfds/logout-method", "rfds/session-delete", - "rfds/message-id", "rfds/diff-delete", "rfds/boolean-config-option", "rfds/elicitation", "rfds/next-edit-suggestions", - "rfds/additional-directories", "rfds/custom-llm-endpoint", - "rfds/streamable-http-websocket-transport" + "rfds/model-config-category", + { + "group": "v2 Draft", + "expanded": true, + "root": "rfds/v2/overview", + "pages": [ + "rfds/v2/prompt", + "rfds/message-id", + "rfds/streamable-http-websocket-transport" + ] + } ] }, { "group": "Preview", - "pages": [] + "pages": ["rfds/rust-sdk-v1", "rfds/additional-directories"] }, { "group": "Completed", @@ -146,7 +167,8 @@ "rfds/session-info-update", "rfds/acp-agent-registry", "rfds/session-resume", - "rfds/session-close" + "rfds/session-close", + "rfds/logout-method" ] } ] @@ -172,6 +194,7 @@ { "group": "Announcements", "pages": [ + "announcements/logout-method-stabilized", "announcements/session-close-stabilized", "announcements/session-resume-stabilized", "announcements/transports-working-group", diff --git a/docs/get-started/clients.mdx b/docs/get-started/clients.mdx index 6db2fb3a0..3ca9e71de 100644 --- a/docs/get-started/clients.mdx +++ b/docs/get-started/clients.mdx @@ -20,31 +20,35 @@ The following projects implement ACP directly, connect ACP agents to other envir - Visual Studio Code — through the [ACP Client](https://github.com/formulahendry/vscode-acp) extension - [Zed](https://zed.dev/docs/ai/external-agents) -## Clients and apps +## CLI and TUI -- [ACP UI](https://github.com/formulahendry/acp-ui) - [acpx (CLI)](https://github.com/openclaw/acpx) -- [gemini-cli-desktop](https://github.com/Piebald-AI/gemini-cli-desktop) +- [Nori CLI](https://github.com/tilework-tech/nori-cli) +- [pool](https://github.com/poolsideai/pool) +- [Toad](https://www.batrachian.ai/) + +## Desktop and Web + +- [ACP UI](https://github.com/formulahendry/acp-ui) (Windows, macOS, Linux, iOS, Android, Web) - [Agent Studio](https://github.com/sxhxliang/agent-studio) +- [AgentRQ](https://github.com/agentrq/agentrq) — Human-in-the-loop realtime task management and collaboration (Web) - [AionUi](https://github.com/iOfficeAI/AionUi) - [aizen](https://aizen.win) - [DeepChat](https://github.com/ThinkInAIXYZ/deepchat) - [fabriqa.ai](https://fabriqa.ai) +- [gemini-cli-desktop](https://github.com/Piebald-AI/gemini-cli-desktop) - [Harnss](https://github.com/OpenSource03/harnss) -- [iflow-cli](https://github.com/iflow-ai/iflow-cli) - [Jockey](https://github.com/recailai/jockey) — open-source multi-agent orchestrator (Tauri + Rust + SolidJS) that coordinates Claude Code, Gemini CLI, and Codex CLI via ACP - [Lody](https://lody.ai) - [Minion Mind](https://minion-mind.nebulame.com/) — through the [Agent Client](https://github.com/RAIT-09/obsidian-agent-client) plugin - [Mitto](https://github.com/inercia/mitto) -- [Nori CLI](https://github.com/tilework-tech/nori-cli) - [Ngent](https://github.com/beyond5959/ngent) -- [pool](https://github.com/poolsideai/pool) - [RayClaw](https://github.com/rayclaw/rayclaw?tab=readme-ov-file#acp-agent-client-protocol) - [RLM Code](https://github.com/SuperagenticAI/rlm-code) - [Sidequery _(coming soon)_](https://sidequery.dev) - [Tidewave](https://tidewave.ai/) -- [Toad](https://www.batrachian.ai/) - [Web Browser with AI SDK](https://github.com/mcpc-tech/ai-elements-remix-template) (powered by [@mcpc/acp-ai-provider](https://github.com/mcpc-tech/mcpc/tree/main/packages/acp-ai-provider)) +- [ACP Components](https://github.com/zvzuola/acp-components) - A universal frontend component library for building AI Agent interfaces based on the ACP ## Notebook and data tools @@ -70,6 +74,7 @@ These mobile-first tools bring ACP and related coding-agent workflows to phones - [Telegram ACP Bot](https://github.com/mgaitan/telegram-acp-bot) (Telegram) — through the [`telegram-acp-bot`](https://github.com/mgaitan/telegram-acp-bot) connector - [Telegram-ACP](https://github.com/SuperKenVery/Telegram-ACP/) (Telegram) — Supports multi-thread chat and message streaming - [WeChat ACP](https://github.com/formulahendry/wechat-acp) (WeChat) +- [Sniptail](https://github.com/Justkog/sniptail) (Discord, Slack) - self-hosted chat bridge for running coding agents across your team’s repositories ## Frameworks @@ -86,6 +91,7 @@ These frameworks add ACP support through dedicated integrations or adapters: These connectors bridge ACP into other environments and transport layers: +- [ACP to AG-UI](https://github.com/namanrajpal/acp-to-agui) — bridges any ACP agent to web frontends via [AG-UI](https://docs.ag-ui.com) events over SSE; works with CopilotKit, AG-UI HttpAgent, or custom UIs (Web) - [AgentRQ](https://github.com/agentrq/acp-gateway) — bridges stdio-based ACP agents to the AgentRQ - Human-in-the-loop task collaboration service using MCP server. - [Aptove Bridge](https://github.com/aptove/bridge) — bridges stdio-based ACP agents to the Aptove mobile client over WebSocket - [OpenClaw](https://docs.openclaw.ai/cli/acp) — through the [`openclaw acp`](https://docs.openclaw.ai/cli/acp) bridge to an OpenClaw Gateway diff --git a/docs/get-started/registry.mdx b/docs/get-started/registry.mdx index 6bd2ea7b1..c33338e52 100644 --- a/docs/get-started/registry.mdx +++ b/docs/get-started/registry.mdx @@ -67,7 +67,7 @@ Visit [the registry repository on GitHub](https://github.com/agentclientprotocol > Augment Code's powerful software agent, backed by industry-leading context engine - **0.24.0**, + **0.27.2**, ACP wrapper for Anthropic's Claude - **0.31.4**, + **0.37.0**, Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more - **2.17.0**, + **3.0.10**, Tencent Cloud's official intelligent coding tool - **2.94.3** + **2.97.4** ACP adapter for OpenAI's coding assistant - **0.12.0**, + **0.14.0**, + + + Co-building with a seasoned Rust partner. - **0.5.1**, + **0.6.0**, Minimal ACP Native Coding Agent - **0.1.20**, + **0.1.23**, Cursor's coding agent - **2026.03.30** + **2026.05.20** A coding agent that puts leading models at your command. - **0.0.51** + **0.0.66** Reduces API costs by more than 50%, produces better and faster work. Uses Hash anchored parallel edits, AST manipulation and a whole lot of neat optimizations. Fully Open Source. - **0.3.4**, + **0.3.44**, Factory Droid - AI coding agent powered by Factory AI - **0.112.0** + **0.131.0** Code and build agents with comprehensive multi-provider support - **0.6.25**, + **0.7.8**, Google's official CLI for Gemini - **0.40.0**, + **0.43.0**, GitHub's AI pair programmer - **1.0.39**, + **1.0.51**, ACP agent powered by Zhipu AI's GLM Coding Plan models (glm-5.1, glm-5-turbo, glm-4.7, glm-4.5-air). Supports streaming, tool calls, mid-session model switching, image input via Z.AI Coding Plan Vision MCP, and session load/fork/resume with on-disk persistence. - **1.0.0**, + **1.1.4**, A local, extensible, open source AI agent that automates engineering tasks - **1.33.1**, + **1.35.0**, AI Coding Agent by JetBrains - **1468.30.0**, + **1668.43.0**, The open source coding agent - **7.2.25**, + **7.3.1**, Moonshot AI's coding assistant - **1.40.0**, + **1.44.0**, Mistral's open-source coding assistant - **2.9.0**, + **2.10.1**, Nova by Compass AI - a fully-fledged software engineer at your command - **1.1.1**, + **1.1.9**, The open source coding agent - **1.14.29**, + **1.15.7**, ACP adapter for pi coding agent - **0.0.26**, + **0.0.27**, AI coding assistant with agentic capabilities - **0.2.4** + **0.2.14** Alibaba's Qwen coding assistant - **0.15.5**, + **0.16.0**, Open-source DevOps agent in Rust with enterprise-grade security - **0.3.78**, + **0.3.82**, + +```mermaid +sequenceDiagram + participant Client + participant Agent + + Client->>Agent: initialize + Agent-->>Client: initialize response (authMethods, auth.logout) + + alt Agent requires authentication + Client->>Agent: authenticate (methodId) + Agent-->>Client: authenticate response + end + + Note over Client,Agent: Authenticated requests may proceed + + alt User logs out + Client->>Agent: logout + Agent-->>Client: logout response + end + + Note over Client,Agent: New sessions require authentication again +``` + +
+ +## Advertising Authentication + +Agents advertise authentication options in the `authMethods` field of the `initialize` response. Each method has an `id` that the Client passes back to the Agent in a later `authenticate` request. + +Agents that support `logout` also advertise `agentCapabilities.auth.logout`: + +```json highlight={7-11,12-18} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "auth": { + "logout": {} + } + }, + "authMethods": [ + { + "id": "agent-login", + "name": "Agent login", + "description": "Sign in using the agent's login flow" + } + ] + } +} +``` + +If `agentCapabilities.auth.logout` is omitted or `null`, the Agent does not support `logout` and Clients **MUST NOT** call it. Supplying `{}` means the Agent supports the method. + +### Authentication Method Types + +The default authentication method type is `agent`, where the Agent handles authentication itself. When no `type` is present, the method is treated as `agent`: + +```json +{ + "id": "agent-login", + "name": "Agent login", + "description": "Sign in using the agent's login flow" +} +``` + +An explicit `"type": "agent"` is also accepted but not required. + +See the [schema](/protocol/schema#authmethod) for the full stable `AuthMethod` definition. + +## Authenticating + +When an Agent requires authentication before allowing session creation, the Client calls `authenticate` with one of the advertised authentication method IDs: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "authenticate", + "params": { + "methodId": "agent-login" + } +} +``` + + + The ID of the authentication method to use. This value must match one of the + methods advertised in the `initialize` response. + + +On success, the Agent returns an empty result: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": {} +} +``` + +After successful authentication, the Client can create new sessions without receiving an `auth_required` error for authentication-gated requests. + +## Logging Out + +The `logout` method allows Clients to end the current authenticated state. Clients should only call it after verifying the Agent advertised `agentCapabilities.auth.logout` during initialization. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "logout", + "params": {} +} +``` + +On success, the Agent returns an empty result: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "result": {} +} +``` + +After a successful `logout`, new sessions that require authentication will require the Client to call `authenticate` again. + +## Active Sessions + +The protocol does not guarantee what happens to already-running sessions after `logout`. Agents may terminate them, keep them running, or return `auth_required` errors for future session activity. + +Clients **SHOULD** be prepared for active session operations to fail with authentication-related errors after logout and should prompt the user to authenticate again when appropriate. diff --git a/docs/protocol/draft/agent-plan.mdx b/docs/protocol/draft/agent-plan.mdx new file mode 100644 index 000000000..874572a72 --- /dev/null +++ b/docs/protocol/draft/agent-plan.mdx @@ -0,0 +1,83 @@ +--- +title: "Agent Plan" +description: "How Agents communicate their execution plans" +--- + +Plans are execution strategies for complex tasks that require multiple steps. + +Agents may share plans with Clients through [`session/update`](./prompt-turn#3-agent-reports-output) notifications, providing real-time visibility into their thinking and progress. + +## Creating Plans + +When the language model creates an execution plan, the Agent **SHOULD** report it to the Client: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "plan", + "entries": [ + { + "content": "Analyze the existing codebase structure", + "priority": "high", + "status": "pending" + }, + { + "content": "Identify components that need refactoring", + "priority": "high", + "status": "pending" + }, + { + "content": "Create unit tests for critical functions", + "priority": "medium", + "status": "pending" + } + ] + } + } +} +``` + + + An array of [plan entries](#plan-entries) representing the tasks to be + accomplished + + +## Plan Entries + +Each plan entry represents a specific task or goal within the overall execution strategy: + + + A human-readable description of what this task aims to accomplish + + + + The relative importance of this task. + +- `high` +- `medium` +- `low` + + + + + The current [execution status](#status) of this task + +- `pending` +- `in_progress` +- `completed` + + + +## Updating Plans + +As the Agent progresses through the plan, it **SHOULD** report updates by sending more `session/update` notifications with the same structure. + +The Agent **MUST** send a complete list of all plan entries in each update and their current status. The Client **MUST** replace the current plan completely. + +### Dynamic Planning + +Plans can evolve during execution. The Agent **MAY** add, remove, or modify plan entries as it discovers new requirements or completes tasks, allowing it to adapt based on what it learns. diff --git a/docs/protocol/draft/authentication.mdx b/docs/protocol/draft/authentication.mdx new file mode 100644 index 000000000..7f7fe8a1d --- /dev/null +++ b/docs/protocol/draft/authentication.mdx @@ -0,0 +1,163 @@ +--- +title: "Authentication" +description: "Authenticating with agents and logging out" +--- + +ACP authentication is negotiated during [initialization](/protocol/initialization). Agents advertise available authentication methods in `authMethods`, Clients choose one by calling `authenticate`, and Agents that support ending an authenticated state advertise the `logout` capability. + +
+ +```mermaid +sequenceDiagram + participant Client + participant Agent + + Client->>Agent: initialize + Agent-->>Client: initialize response (authMethods, auth.logout) + + alt Agent requires authentication + Client->>Agent: authenticate (methodId) + Agent-->>Client: authenticate response + end + + Note over Client,Agent: Authenticated requests may proceed + + alt User logs out + Client->>Agent: logout + Agent-->>Client: logout response + end + + Note over Client,Agent: New sessions require authentication again +``` + +
+ +## Advertising Authentication + +Agents advertise authentication options in the `authMethods` field of the `initialize` response. Each method has an `id` that the Client passes back to the Agent in a later `authenticate` request. + +Agents that support `logout` also advertise `agentCapabilities.auth.logout`: + +```json highlight={7-11,12-18} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "auth": { + "logout": {} + } + }, + "authMethods": [ + { + "id": "agent-login", + "name": "Agent login", + "description": "Sign in using the agent's login flow" + } + ] + } +} +``` + +If `agentCapabilities.auth.logout` is omitted or `null`, the Agent does not support `logout` and Clients **MUST NOT** call it. Supplying `{}` means the Agent supports the method. + +### Authentication method types + +The default authentication method type is `agent`, where the Agent handles authentication itself. When no `type` is present, the method is treated as `agent`: + +```json +{ + "id": "agent-login", + "name": "Agent login", + "description": "Sign in using the agent's login flow" +} +``` + +Draft authentication method types provide additional information so Clients can offer better UI: + +- `env_var`: the user provides credentials that the Client passes to the Agent as environment variables. +- `terminal`: the Client runs the Agent's terminal authentication flow for the user. + +`terminal` methods require Client support. Clients advertise this during initialization with `clientCapabilities.auth.terminal`: + +```json highlight={7-9} +{ + "jsonrpc": "2.0", + "id": 0, + "method": "initialize", + "params": { + "protocolVersion": 1, + "clientCapabilities": { + "auth": { + "terminal": true + } + } + } +} +``` + +See the [draft schema](/protocol/draft/schema#authmethod) for the full `AuthMethod` definitions. + +## Authenticating + +When an Agent requires authentication before allowing session creation, the Client calls `authenticate` with one of the advertised authentication method IDs: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "authenticate", + "params": { + "methodId": "agent-login" + } +} +``` + + + The ID of the authentication method to use. This value must match one of the + methods advertised in the `initialize` response. + + +On success, the Agent returns an empty result: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": {} +} +``` + +After successful authentication, the Client can create new sessions without receiving an `auth_required` error for authentication-gated requests. + +## Logging Out + +The `logout` method allows Clients to end the current authenticated state. Clients should only call it after verifying the Agent advertised `agentCapabilities.auth.logout` during initialization. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "logout", + "params": {} +} +``` + +On success, the Agent returns an empty result: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "result": {} +} +``` + +After a successful `logout`, new sessions that require authentication will require the Client to call `authenticate` again. + +## Active Sessions + +The protocol does not guarantee what happens to already-running sessions after `logout`. Agents may terminate them, keep them running, or return `auth_required` errors for future session activity. + +Clients **SHOULD** be prepared for active session operations to fail with authentication-related errors after logout and should prompt the user to authenticate again when appropriate. diff --git a/docs/protocol/draft/content.mdx b/docs/protocol/draft/content.mdx new file mode 100644 index 000000000..931f451eb --- /dev/null +++ b/docs/protocol/draft/content.mdx @@ -0,0 +1,204 @@ +--- +title: "Content" +description: "Understanding content blocks in the Agent Client Protocol" +--- + +Content blocks represent displayable information that flows through the Agent Client Protocol. They provide a structured way to handle various types of user-facing content—whether it's text from language models, images for analysis, or embedded resources for context. + +Content blocks appear in: + +- User prompts sent via [`session/prompt`](./prompt-turn#1-user-message) +- Language model output streamed through [`session/update`](./prompt-turn#3-agent-reports-output) notifications +- Progress updates and results from [tool calls](./tool-calls) + +## Content Types + +The Agent Client Protocol uses the same `ContentBlock` structure as the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2025-06-18/schema#contentblock). + +This design choice enables Agents to seamlessly forward content from MCP tool outputs without transformation. + +### Text Content + +Plain text messages form the foundation of most interactions. + +```json +{ + "type": "text", + "text": "What's the weather like today?" +} +``` + +All Agents **MUST** support text content blocks when included in prompts. + + + The text content to display + + + + Optional metadata about how the content should be used or displayed. [Learn + more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + + +### Image Content + +Images can be included for visual context or analysis. + +```json +{ + "type": "image", + "mimeType": "image/png", + "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB..." +} +``` + + Requires the `image` [prompt +capability](./initialization#prompt-capabilities) when included in prompts. + + + Base64-encoded image data + + + + The MIME type of the image (e.g., "image/png", "image/jpeg") + + + + Optional URI reference for the image source + + + + Optional metadata about how the content should be used or displayed. [Learn + more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + + +### Audio Content + +Audio data for transcription or analysis. + +```json +{ + "type": "audio", + "mimeType": "audio/wav", + "data": "UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAAB..." +} +``` + + Requires the `audio` [prompt +capability](./initialization#prompt-capabilities) when included in prompts. + + + Base64-encoded audio data + + + + The MIME type of the audio (e.g., "audio/wav", "audio/mp3") + + + + Optional metadata about how the content should be used or displayed. [Learn + more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + + +### Embedded Resource + +Complete resource contents embedded directly in the message. + +```json +{ + "type": "resource", + "resource": { + "uri": "file:///home/user/script.py", + "mimeType": "text/x-python", + "text": "def hello():\n print('Hello, world!')" + } +} +``` + +This is the preferred way to include context in prompts, such as when using @-mentions to reference files or other resources. + +By embedding the content directly in the request, Clients can include context from sources that the Agent may not have direct access to. + + Requires the `embeddedContext` [prompt +capability](./initialization#prompt-capabilities) when included in prompts. + + + The embedded resource contents, which can be either: + + + + The URI identifying the resource + + + + The text content of the resource + + + + Optional MIME type of the text content + + + + + + + The URI identifying the resource + + + + Base64-encoded binary data + + + + Optional MIME type of the blob + + + + + + + Optional metadata about how the content should be used or displayed. [Learn + more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + + +### Resource Link + +References to resources that the Agent can access. + +```json +{ + "type": "resource_link", + "uri": "file:///home/user/document.pdf", + "name": "document.pdf", + "mimeType": "application/pdf", + "size": 1024000 +} +``` + + + The URI of the resource + + + + A human-readable name for the resource + + + + The MIME type of the resource + + + + Optional display title for the resource + + + + Optional description of the resource contents + + + + Optional size of the resource in bytes + + + + Optional metadata about how the content should be used or displayed. [Learn + more](https://modelcontextprotocol.io/specification/2025-06-18/server/resources#annotations). + diff --git a/docs/protocol/draft/error.mdx b/docs/protocol/draft/error.mdx new file mode 100644 index 000000000..01d1aba38 --- /dev/null +++ b/docs/protocol/draft/error.mdx @@ -0,0 +1,6 @@ +--- +title: "Error" +description: "Error handling in the Agent Client Protocol" +--- + +_Documentation coming soon_ diff --git a/docs/protocol/draft/extensibility.mdx b/docs/protocol/draft/extensibility.mdx new file mode 100644 index 000000000..314410132 --- /dev/null +++ b/docs/protocol/draft/extensibility.mdx @@ -0,0 +1,134 @@ +--- +title: "Extensibility" +description: "Adding custom data and capabilities" +--- + +The Agent Client Protocol provides built-in extension mechanisms that allow implementations to add custom functionality while maintaining compatibility with the core protocol. These mechanisms ensure that Agents and Clients can innovate without breaking interoperability. + +## The `_meta` Field + +All types in the protocol include a `_meta` field with type `{ [key: string]: unknown }` that implementations can use to attach custom information. This includes requests, responses, notifications, and even nested types like content blocks, tool calls, plan entries, and capability objects. + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "session/prompt", + "params": { + "sessionId": "sess_abc123def456", + "prompt": [ + { + "type": "text", + "text": "Hello, world!" + } + ], + "_meta": { + "traceparent": "00-80e1afed08e019fc1110464cfa66635c-7a085853722dc6d2-01", + "zed.dev/debugMode": true + } + } +} +``` + +Clients may propagate fields to the agent for correlation purposes, such as `requestId`. The following root-level keys in `_meta` **SHOULD** be reserved for [W3C trace context](https://www.w3.org/TR/trace-context/) to guarantee interop with existing MCP implementations and OpenTelemetry tooling: + +- `traceparent` +- `tracestate` +- `baggage` + +Implementations **MUST NOT** add any custom fields at the root of a type that's part of the specification. All possible names are reserved for future protocol versions. + +## Extension Methods + +The protocol reserves any method name starting with an underscore (`_`) for custom extensions. This allows implementations to add new functionality without the risk of conflicting with future protocol versions. + +Extension methods follow standard [JSON-RPC 2.0](https://www.jsonrpc.org/specification) semantics: + +- **[Requests](https://www.jsonrpc.org/specification#request_object)** - Include an `id` field and expect a response +- **[Notifications](https://www.jsonrpc.org/specification#notification)** - Omit the `id` field and are one-way + +### Custom Requests + +In addition to the requests specified by the protocol, implementations **MAY** expose and call custom JSON-RPC requests as long as their name starts with an underscore (`_`). + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "_zed.dev/workspace/buffers", + "params": { + "language": "rust" + } +} +``` + +Upon receiving a custom request, implementations **MUST** respond accordingly with the provided `id`: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "buffers": [ + { "id": 0, "path": "/home/user/project/src/main.rs" }, + { "id": 1, "path": "/home/user/project/src/editor.rs" } + ] + } +} +``` + +If the receiving end doesn't recognize the custom method name, it should respond with the standard "Method not found" error: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32601, + "message": "Method not found" + } +} +``` + +To avoid such cases, extensions **SHOULD** advertise their [custom capabilities](#advertising-custom-capabilities) so that callers can check their availability first and adapt their behavior or interface accordingly. + +### Custom Notifications + +Custom notifications are regular JSON-RPC notifications that start with an underscore (`_`). Like all notifications, they omit the `id` field: + +```json +{ + "jsonrpc": "2.0", + "method": "_zed.dev/file_opened", + "params": { + "path": "/home/user/project/src/editor.rs" + } +} +``` + +Unlike with custom requests, implementations **SHOULD** ignore unrecognized notifications. + +## Advertising Custom Capabilities + +Implementations **SHOULD** use the `_meta` field in capability objects to advertise support for extensions and their methods: + +```json +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "loadSession": true, + "_meta": { + "zed.dev": { + "workspace": true, + "fileNotifications": true + } + } + } + } +} +``` + +This allows implementations to negotiate custom features during initialization without breaking compatibility with standard Clients and Agents. diff --git a/docs/protocol/draft/file-system.mdx b/docs/protocol/draft/file-system.mdx index 98c6e3120..d11ff2f51 100644 --- a/docs/protocol/draft/file-system.mdx +++ b/docs/protocol/draft/file-system.mdx @@ -13,7 +13,7 @@ authorize those paths against the session's effective root set. - by default, the effective root set is just `cwd` - if the unstable `sessionCapabilities.additionalDirectories` capability is in use, the effective root set becomes `[cwd, ...additionalDirectories]` - `cwd` remains the base for relative paths; additional roots only expand filesystem scope -- when a Client discovers a session through `session/list`, it SHOULD treat `cwd` plus `SessionInfo.additionalDirectories` as the authoritative current root set until a later lifecycle request changes it +- when a Client discovers a session through `session/list`, it SHOULD use `cwd` together with any `SessionInfo.additionalDirectories` entries returned for that session as the reported root set; omitted and empty values report no additional roots, and any later `session/load` or `session/resume` request establishes the root set explicitly Because ACP filesystem methods are client-mediated, the Client remains responsible for enforcing those root boundaries. diff --git a/docs/protocol/draft/initialization.mdx b/docs/protocol/draft/initialization.mdx new file mode 100644 index 000000000..6a8a3232a --- /dev/null +++ b/docs/protocol/draft/initialization.mdx @@ -0,0 +1,239 @@ +--- +title: "Initialization" +description: "How all Agent Client Protocol connections begin" +--- + +{/* todo! link to all concepts */} + +The Initialization phase allows [Clients](./overview#client) and [Agents](./overview#agent) to negotiate protocol versions, capabilities, and authentication methods. + +
+ +```mermaid +sequenceDiagram + participant Client + participant Agent + + Note over Client, Agent: Connection established + Client->>Agent: initialize + Note right of Agent: Negotiate protocol
version & capabilities + Agent-->>Client: initialize response + Note over Client,Agent: Ready for session setup +``` + +
+ +Before a Session can be created, Clients **MUST** initialize the connection by calling the `initialize` method with: + +- The latest [protocol version](#protocol-version) supported +- The [capabilities](#client-capabilities) supported + +They **SHOULD** also provide a name and version to the Agent. + +```json +{ + "jsonrpc": "2.0", + "id": 0, + "method": "initialize", + "params": { + "protocolVersion": 1, + "clientCapabilities": { + "fs": { + "readTextFile": true, + "writeTextFile": true + }, + "terminal": true + }, + "clientInfo": { + "name": "my-client", + "title": "My Client", + "version": "1.0.0" + } + } +} +``` + +The Agent **MUST** respond with the chosen [protocol version](#protocol-version) and the [capabilities](#agent-capabilities) it supports. It **SHOULD** also provide a name and version to the Client as well: + +```json +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "loadSession": true, + "promptCapabilities": { + "image": true, + "audio": true, + "embeddedContext": true + }, + "mcpCapabilities": { + "http": true, + "sse": true + } + }, + "agentInfo": { + "name": "my-agent", + "title": "My Agent", + "version": "1.0.0" + }, + "authMethods": [] + } +} +``` + +## Protocol version + +The protocol versions that appear in the `initialize` requests and responses are a single integer that identifies a **MAJOR** protocol version. This version is only incremented when breaking changes are introduced. + +Clients and Agents **MUST** agree on a protocol version and act according to its specification. + +See [Capabilities](#capabilities) to learn how non-breaking features are introduced. + +### Version Negotiation + +The `initialize` request **MUST** include the latest protocol version the Client supports. + +If the Agent supports the requested version, it **MUST** respond with the same version. Otherwise, the Agent **MUST** respond with the latest version it supports. + +If the Client does not support the version specified by the Agent in the `initialize` response, the Client **SHOULD** close the connection and inform the user about it. + +## Capabilities + +Capabilities describe features supported by the Client and the Agent. + +All capabilities included in the `initialize` request are **OPTIONAL**. Clients and Agents **SHOULD** support all possible combinations of their peer's capabilities. + +The introduction of new capabilities is not considered a breaking change. Therefore, Clients and Agents **MUST** treat all capabilities omitted in the `initialize` request as **UNSUPPORTED**. + +Capabilities are high-level and are not attached to a specific base protocol concept. + +Capabilities may specify the availability of protocol methods, notifications, or a subset of their parameters. They may also signal behaviors of the Agent or Client implementation. + +Implementations can also [advertise custom capabilities](./extensibility#advertising-custom-capabilities) using the `_meta` field to indicate support for protocol extensions. + +### Client Capabilities + +The Client **SHOULD** specify whether it supports the following capabilities: + +#### File System + + + The `fs/read_text_file` method is available. + + + + The `fs/write_text_file` method is available. + + + + Learn more about File System methods + + +#### Terminal + + + All `terminal/*` methods are available, allowing the Agent to execute and + manage shell commands. + + + + Learn more about Terminals + + +### Agent Capabilities + +The Agent **SHOULD** specify whether it supports the following capabilities: + + + The [`session/load`](./session-setup#loading-sessions) method is available. + + + + Object indicating the different types of [content](./content) that may be + included in `session/prompt` requests. + + + + Authentication-related capabilities supported by the Agent. + + +#### Prompt capabilities + +As a baseline, all Agents **MUST** support `ContentBlock::Text` and `ContentBlock::ResourceLink` in `session/prompt` requests. + +Optionally, they **MAY** support richer types of [content](./content) by specifying the following capabilities: + + + The prompt may include `ContentBlock::Image` + + + + The prompt may include `ContentBlock::Audio` + + + + The prompt may include `ContentBlock::Resource` + + +#### MCP capabilities + + + The Agent supports connecting to MCP servers over HTTP. + + + + The Agent supports connecting to MCP servers over SSE. + +Note: This transport has been deprecated by the MCP spec. + + + +#### Authentication Capabilities + + + The [`logout`](./authentication#logging-out) method is available. + + + + Learn more about Authentication + + +#### Session Capabilities + +As a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`. + +Optionally, they **MAY** support other session methods and notifications by specifying additional capabilities. + + + `session/load` is still handled by the top-level `load_session` capability. + This will be unified in future versions of the protocol. + + +## Implementation Information + +Both Clients and Agents **SHOULD** provide information about their implementation in the `clientInfo` and `agentInfo` fields respectively. Both take the following three fields: + + + Intended for programmatic or logical use, but can be used as a display name + fallback if title isn’t present. + + + + Intended for UI and end-user contexts — optimized to be human-readable and + easily understood. If not provided, the name should be used for display. + + + + Version of the implementation. Can be displayed to the user or used for + debugging or metrics purposes. + + + + Note: in future versions of the protocol, this information will be required. + + +--- + +Once the connection is initialized, you're ready to [create a session](./session-setup) and begin the conversation with the Agent. diff --git a/docs/protocol/draft/overview.mdx b/docs/protocol/draft/overview.mdx new file mode 100644 index 000000000..5bfdbb0a9 --- /dev/null +++ b/docs/protocol/draft/overview.mdx @@ -0,0 +1,219 @@ +--- +title: "Overview" +description: "How the Agent Client Protocol works" +--- + +The Agent Client Protocol allows [Agents](#agent) and [Clients](#client) to communicate by exposing methods that each side can call and sending notifications to inform each other of events. + +## Communication Model + +The protocol follows the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification with two types of messages: + +- **Methods**: Request-response pairs that expect a result or error +- **Notifications**: One-way messages that don't expect a response + +## Message Flow + +A typical flow follows this pattern: + + + + +- Client → Agent: `initialize` to establish connection +- Client → Agent: `authenticate` if required by the Agent + + + + + +- Client → Agent: `session/new` to create a new session +- Client → Agent: `session/load` to resume an existing session if supported + + + + + - Client → Agent: `session/prompt` to send user message + - Agent → Client: `session/update` notifications for progress updates + - Agent → Client: File operations or permission requests as needed + - Client → Agent: `session/cancel` to interrupt processing if needed + - Turn ends and the Agent sends the `session/prompt` response with a stop reason + + + +## Agent + +Agents are programs that use generative AI to autonomously modify code. They typically run as subprocesses of the Client. + +### Baseline Methods + +Schema]} +> + [Negotiate versions and exchange capabilities.](./initialization). + + +Schema]} +> + Authenticate with the Agent (if required). + + +Schema]} +> + [Create a new conversation session](./session-setup#creating-a-session). + + +Schema]} +> + [Send user prompts](./prompt-turn#1-user-message) to the Agent. + + +### Optional Methods + +Schema]} +> + [Load an existing session](./session-setup#loading-sessions) (requires + `loadSession` capability). + + +Schema]}> + [End the current authenticated state](./authentication#logging-out) (requires + `agentCapabilities.auth.logout` capability). + + +Schema]} +> + [Switch between agent operating + modes](./session-modes#setting-the-current-mode). + + +### Notifications + +Schema]} +> + [Cancel ongoing operations](./prompt-turn#cancellation) (no response + expected). + + +## Client + +Clients provide the interface between users and agents. They are typically code editors (IDEs, text editors) but can also be other UIs for interacting with agents. Clients manage the environment, handle user interactions, and control access to resources. + +### Baseline Methods + +Schema]} +> + [Request user authorization](./tool-calls#requesting-permission) for tool + calls. + + +### Optional Methods + +Schema]} +> + [Read file contents](./file-system#reading-files) (requires `fs.readTextFile` + capability). + + +Schema]} +> + [Write file contents](./file-system#writing-files) (requires + `fs.writeTextFile` capability). + + +Schema]} +> + [Create a new terminal](./terminals) (requires `terminal` capability). + + +Schema]} +> + Get terminal output and exit status (requires `terminal` capability). + + +Schema]} +> + Release a terminal (requires `terminal` capability). + + +Schema]} +> + Wait for terminal command to exit (requires `terminal` capability). + + +Schema]} +> + Kill terminal command without releasing (requires `terminal` capability). + + +### Notifications + +Schema]} +> + [Send session updates](./prompt-turn#3-agent-reports-output) to inform the + Client of changes (no response expected). This includes: - [Message + chunks](./content) (agent, user, thought) - [Tool calls and + updates](./tool-calls) - [Plans](./agent-plan) - [Available commands + updates](./slash-commands#advertising-commands) - [Mode + changes](./session-modes#from-the-agent) + + +## Argument requirements + +- All file paths in the protocol **MUST** be absolute. +- Line numbers are 1-based + +## Error Handling + +All methods follow standard JSON-RPC 2.0 [error handling](https://www.jsonrpc.org/specification#error_object): + +- Successful responses include a `result` field +- Errors include an `error` object with `code` and `message` +- Notifications never receive responses (success or error) + +## Extensibility + +The protocol provides built-in mechanisms for adding custom functionality while maintaining compatibility: + +- Add custom data using `_meta` fields +- Create custom methods by prefixing their name with underscore (`_`) +- Advertise custom capabilities during initialization + +Learn about [protocol extensibility](./extensibility) to understand how to use these mechanisms. + +## Next Steps + +- Learn about [Initialization](./initialization) to understand version and capability negotiation +- Understand [Session Setup](./session-setup) for creating and loading sessions +- Review the [Prompt Turn](./prompt-turn) lifecycle +- Explore [Extensibility](./extensibility) to add custom features diff --git a/docs/protocol/draft/prompt-turn.mdx b/docs/protocol/draft/prompt-turn.mdx new file mode 100644 index 000000000..57e8df34f --- /dev/null +++ b/docs/protocol/draft/prompt-turn.mdx @@ -0,0 +1,319 @@ +--- +title: "Prompt Turn" +description: "Understanding the core conversation flow" +--- + +A prompt turn represents a complete interaction cycle between the [Client](./overview#client) and [Agent](./overview#agent), starting with a user message and continuing until the Agent completes its response. This may involve multiple exchanges with the language model and tool invocations. + +Before sending prompts, Clients **MUST** first complete the [initialization](./initialization) phase and [session setup](./session-setup). + +## The Prompt Turn Lifecycle + +A prompt turn follows a structured flow that enables rich interactions between the user, Agent, and any connected tools. + +
+ +```mermaid +sequenceDiagram + participant Client + participant Agent + + Note over Agent,Client: Session ready + + Note left of Client: User sends message + Client->>Agent: session/prompt (user message) + Note right of Agent: Process with LLM + + loop Until completion + Note right of Agent: LLM responds with
content/tool calls + Agent->>Client: session/update (plan) + Agent->>Client: session/update (agent_message_chunk) + + opt Tool calls requested + Agent->>Client: session/update (tool_call) + opt Permission required + Agent->>Client: session/request_permission + Note left of Client: User grants/denies + Client-->>Agent: Permission response + end + Agent->>Client: session/update (tool_call status: in_progress) + Note right of Agent: Execute tool + Agent->>Client: session/update (tool_call status: completed) + Note right of Agent: Send tool results
back to LLM + end + + opt User cancelled during execution + Note left of Client: User cancels prompt + Client->>Agent: session/cancel + Note right of Agent: Abort operations + Agent-->>Client: session/prompt response (cancelled) + end + end + + Agent-->>Client: session/prompt response (stopReason) + +``` + +### 1. User Message + +The turn begins when the Client sends a `session/prompt`: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/prompt", + "params": { + "sessionId": "sess_abc123def456", + "prompt": [ + { + "type": "text", + "text": "Can you analyze this code for potential issues?" + }, + { + "type": "resource", + "resource": { + "uri": "file:///home/user/project/main.py", + "mimeType": "text/x-python", + "text": "def process_data(items):\n for item in items:\n print(item)" + } + } + ] + } +} +``` + + + The [ID](./session-setup#session-id) of the session to send this message to. + + + The contents of the user message, e.g. text, images, files, etc. + + Clients **MUST** restrict types of content according to the [Prompt Capabilities](./initialization#prompt-capabilities) established during [initialization](./initialization). + + + Learn more about Content + + + + +### 2. Agent Processing + +Upon receiving the prompt request, the Agent processes the user's message and sends it to the language model, which **MAY** respond with text content, tool calls, or both. + +### 3. Agent Reports Output + +The Agent reports the model's output to the Client via `session/update` notifications. This may include the Agent's plan for accomplishing the task: + +```json expandable +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "plan", + "entries": [ + { + "content": "Check for syntax errors", + "priority": "high", + "status": "pending" + }, + { + "content": "Identify potential type issues", + "priority": "medium", + "status": "pending" + }, + { + "content": "Review error handling patterns", + "priority": "medium", + "status": "pending" + }, + { + "content": "Suggest improvements", + "priority": "low", + "status": "pending" + } + ] + } + } +} +``` + + + Learn more about Agent Plans + + +The Agent then reports text responses from the model: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "agent_message_chunk", + "content": { + "type": "text", + "text": "I'll analyze your code for potential issues. Let me examine it..." + } + } + } +} +``` + +If the model requested tool calls, these are also reported immediately: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "tool_call", + "toolCallId": "call_001", + "title": "Analyzing Python code", + "kind": "other", + "status": "pending" + } + } +} +``` + +### 4. Check for Completion + +If there are no pending tool calls, the turn ends and the Agent **MUST** respond to the original `session/prompt` request with a `StopReason`: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "result": { + "stopReason": "end_turn" + } +} +``` + +Agents **MAY** stop the turn at any point by returning the corresponding [`StopReason`](#stop-reasons). + +### 5. Tool Invocation and Status Reporting + +Before proceeding with execution, the Agent **MAY** request permission from the Client via the `session/request_permission` method. + +Once permission is granted (if required), the Agent **SHOULD** invoke the tool and report a status update marking the tool as `in_progress`: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "tool_call_update", + "toolCallId": "call_001", + "status": "in_progress" + } + } +} +``` + +As the tool runs, the Agent **MAY** send additional updates, providing real-time feedback about tool execution progress. + +While tools execute on the Agent, they **MAY** leverage Client capabilities such as the file system (`fs`) methods to access resources within the Client's environment. + +When the tool completes, the Agent sends another update with the final status and any content: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "tool_call_update", + "toolCallId": "call_001", + "status": "completed", + "content": [ + { + "type": "content", + "content": { + "type": "text", + "text": "Analysis complete:\n- No syntax errors found\n- Consider adding type hints for better clarity\n- The function could benefit from error handling for empty lists" + } + } + ] + } + } +} +``` + + + Learn more about Tool Calls + + +### 6. Continue Conversation + +The Agent sends the tool results back to the language model as another request. + +The cycle returns to [step 2](#2-agent-processing), continuing until the language model completes its response without requesting additional tool calls or the turn gets stopped by the Agent or cancelled by the Client. + +## Stop Reasons + +When an Agent stops a turn, it must specify the corresponding `StopReason`: + + + The language model finishes responding without requesting more tools + + + + The maximum token limit is reached + + + + The maximum number of model requests in a single turn is exceeded + + +The Agent refuses to continue + +The Client cancels the turn + +## Cancellation + +Clients **MAY** cancel an ongoing prompt turn at any time by sending a `session/cancel` notification: + +```json +{ + "jsonrpc": "2.0", + "method": "session/cancel", + "params": { + "sessionId": "sess_abc123def456" + } +} +``` + +The Client **SHOULD** preemptively mark all non-finished tool calls pertaining to the current turn as `cancelled` as soon as it sends the `session/cancel` notification. + +The Client **MUST** respond to all pending `session/request_permission` requests with the `cancelled` outcome. + +When the Agent receives this notification, it **SHOULD** stop all language model requests and all tool call invocations as soon as possible. + +After all ongoing operations have been successfully aborted and pending updates have been sent, the Agent **MUST** respond to the original `session/prompt` request with the `cancelled` [stop reason](#stop-reasons). + + + API client libraries and tools often throw an exception when their operation is aborted, which may propagate as an error response to `session/prompt`. + +Clients often display unrecognized errors from the Agent to the user, which would be undesirable for cancellations as they aren't considered errors. + +Agents **MUST** catch these errors and return the semantically meaningful `cancelled` stop reason, so that Clients can reliably confirm the cancellation. + + + +The Agent **MAY** send `session/update` notifications with content or tool call updates after receiving the `session/cancel` notification, but it **MUST** ensure that it does so before responding to the `session/prompt` request. + +The Client **SHOULD** still accept tool call updates received after sending `session/cancel`. + +--- + +Once a prompt turn completes, the Client may send another `session/prompt` to continue the conversation, building on the context established in previous turns. diff --git a/docs/protocol/draft/schema-v2.mdx b/docs/protocol/draft/schema-v2.mdx index b97b07c33..a60e3c514 100644 --- a/docs/protocol/draft/schema-v2.mdx +++ b/docs/protocol/draft/schema-v2.mdx @@ -3,6 +3,11 @@ title: "Schema" description: "Schema definitions for the Agent Client Protocol" --- + + The schema file can be downloaded directly from the [latest GitHub + release](https://github.com/agentclientprotocol/agent-client-protocol/releases/latest/download/schema.json). + + ## Agent Defines the interface that all ACP-compliant agents must implement. @@ -309,7 +314,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte AgentCapabilities} > Capabilities supported by the agent. - - Default: `{"auth":{},"loadSession":false,"mcpCapabilities":{"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false},"sessionCapabilities":{}}` + - Default: `{"auth":{},"loadSession":false,"mcpCapabilities":{"acp":false,"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false,"promptVariables":false},"sessionCapabilities":{}}` Implementation | null} > @@ -334,10 +339,6 @@ The client should disconnect, if it doesn't support this version. ### logout -**UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - Logs out of the current authenticated state. After a successful logout, all new sessions will require authentication. @@ -345,13 +346,59 @@ There is no guarantee about the behavior of already running sessions. #### LogoutRequest +Request parameters for the logout method. + +Terminates the current authenticated session. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + +#### LogoutResponse + +Response to the `logout` method. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + +### mcp/message + **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for the logout method. +Exchanges an MCP-over-ACP message. -Terminates the current authenticated session. +#### MessageMcpNotification + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Notification parameters for `mcp/message`. + +This is used when the wrapped MCP message is a notification and the outer JSON-RPC +envelope has no `id`. **Type:** Object @@ -365,14 +412,26 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. -#### LogoutResponse +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to the `logout` method. +Request parameters for `mcp/message`. **Type:** Object @@ -386,6 +445,28 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. + +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/message`. + +This is the inner MCP response result payload. Any JSON value is valid. ### nes/accept @@ -633,7 +714,7 @@ This capability is not part of the spec yet, and may be removed or changed at an Disables a provider. -#### DisableProvidersRequest +#### DisableProviderRequest **UNSTABLE** @@ -657,7 +738,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte Provider id to disable. -#### DisableProvidersResponse +#### DisableProviderResponse **UNSTABLE** @@ -741,7 +822,7 @@ This capability is not part of the spec yet, and may be removed or changed at an Replaces the configuration for a provider. -#### SetProvidersRequest +#### SetProviderRequest **UNSTABLE** @@ -777,7 +858,7 @@ May include authorization, routing, or other integration-specific headers. Provider id to configure. -#### SetProvidersResponse +#### SetProviderResponse **UNSTABLE** @@ -889,6 +970,64 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +### session/delete + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Deletes an existing session from `session/list`. + +This method is only available if the agent advertises the `sessionCapabilities.delete` capability. + +#### DeleteSessionRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for deleting an existing session from `session/list`. + +Only available if the Agent supports the `sessionCapabilities.delete` capability. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +SessionId} required> + The ID of the session to delete. + + +#### DeleteSessionResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response from deleting a session. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ### session/fork @@ -1018,17 +1157,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -"string"[]} > - **UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - -Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - -This filter applies only when the field is present and non-empty. When -omitted or empty, no additional-root filter is applied. - Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -1105,7 +1233,8 @@ Additional workspace roots to activate for this session. Each path must be absol When omitted or empty, no additional roots are activated. When non-empty, this is the complete resulting additional-root list for the loaded -session. +session. It may differ from any previously used or reported list as long as +the request `cwd` matches the session's `cwd`. @@ -1398,7 +1527,8 @@ Additional workspace roots to activate for this session. Each path must be absol When omitted or empty, no additional roots are activated. When non-empty, this is the complete resulting additional-root list for the resumed -session. +session. It may differ from any previously used or reported list as long as +the request `cwd` matches the session's `cwd`. @@ -1948,6 +2078,205 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +### mcp/connect + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Opens an MCP-over-ACP connection. + +#### ConnectMcpRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for `mcp/connect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpServerAcpId} required> + The ACP MCP server ID that was provided by the component declaring the MCP server. + + +#### ConnectMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/connect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The unique identifier for this MCP-over-ACP connection. + + + +### mcp/disconnect + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Closes an MCP-over-ACP connection. + +#### DisconnectMcpRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for `mcp/disconnect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The MCP-over-ACP connection to close. + + +#### DisconnectMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/disconnect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + +### mcp/message + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Exchanges an MCP-over-ACP message. + +#### MessageMcpNotification + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Notification parameters for `mcp/message`. + +This is used when the wrapped MCP message is a notification and the outer JSON-RPC +envelope has no `id`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. + +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for `mcp/message`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. + +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/message`. + +This is the inner MCP response result payload. Any JSON value is valid. + ### session/request_permission @@ -2426,10 +2755,6 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte ## AgentAuthCapabilities -**UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - Authentication-related capabilities supported by the agent. **Type:** Object @@ -2473,11 +2798,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte AgentAuthCapabilities} > - **UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - -Authentication-related capabilities supported by the agent. + Authentication-related capabilities supported by the agent. - Default: `{}` @@ -2491,7 +2812,7 @@ Authentication-related capabilities supported by the agent. McpCapabilities} > MCP capabilities supported by the agent. - - Default: `{"http":false,"sse":false}` + - Default: `{"acp":false,"http":false,"sse":false}` NesCapabilities | null} > @@ -2513,7 +2834,7 @@ The position encoding selected by the agent from the client's supported encoding PromptCapabilities} > Prompt capabilities supported by the agent. - - Default: `{"audio":false,"embeddedContext":false,"image":false}` + - Default: `{"audio":false,"embeddedContext":false,"image":false,"promptVariables":false}` ProvidersCapabilities | null} > @@ -3290,6 +3611,40 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +A template that supports variable substitution using \{\{variable_name\}\} syntax. + +Allows dynamic content generation by substituting variables into template strings. +Variables are resolved at processing time and can include values from context, +user input, or system state. + +Requires the `promptVariables` prompt capability when included in prompts. + + + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +Annotations | null} > + + + The template string with \{\{variable_name\}\} placeholders. + + + The discriminator value. Must be `"prompt_template"`. + +PromptVariable[]} required> + Variables available for substitution in this template. + + + + + ## ContentChunk A streamed item of content @@ -4331,10 +4686,6 @@ Protocol names that do not begin with `_` are reserved for the ACP spec. ## LogoutCapabilities -**UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - Logout capabilities supported by the agent. By supplying `\{\}` it means that the agent supports the logout method. @@ -4367,6 +4718,16 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Agent supports `McpServer::Acp`. + + - Default: `false` + Agent supports `McpServer::Http`. @@ -4381,6 +4742,16 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte +## McpConnectionId + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +A unique identifier for an active MCP-over-ACP connection. + +**Type:** `string` + ## McpServer Configuration for connecting to an MCP (Model Context Protocol) server. @@ -4454,6 +4825,43 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +ACP transport configuration + +Only available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`. +The MCP server is provided by an ACP component and communicates over the ACP channel. + + + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpServerAcpId} required> + Unique identifier for this MCP server, generated by the component providing it. + +Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible +on the same ACP connection. + + + + Human-readable name identifying this MCP server. + + + The discriminator value. Must be `"acp"`. + + + + + Stdio transport configuration @@ -4485,6 +4893,54 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte +## McpServerAcp + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +ACP transport configuration for MCP. + +The MCP server is provided by an ACP component and communicates over the ACP channel +using `mcp/connect`, `mcp/message`, and `mcp/disconnect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpServerAcpId} required> + Unique identifier for this MCP server, generated by the component providing it. + +Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible +on the same ACP connection. + + + + Human-readable name identifying this MCP server. + + +## McpServerAcpId + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Unique identifier for an MCP server using the ACP transport. + +The value is opaque and generated by the ACP component providing the MCP server. It is +used by `mcp/connect` to route connection requests back to the component that declared the +server. + +**Type:** `string` + ## McpServerHttp HTTP transport configuration for MCP. @@ -5826,6 +6282,133 @@ in prompt requests for pieces of context that are referenced in the message. - Default: `false` + + Agent supports prompt variables and templates in `session/prompt` requests. + +When enabled, the Client is allowed to include `ContentBlock::PromptTemplate` +in prompt requests with variable substitution support. + + - Default: `false` + + + +## PromptTemplateContent + +A template content block that supports variable substitution. + +Templates use \{\{variable_name\}\} syntax for variable placeholders that can be +substituted with actual values at processing time. This enables dynamic content +generation and reusable prompt templates. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +Annotations | null} > + + + The template string with \{\{variable_name\}\} placeholders. + +PromptVariable[]} required> + Variables available for substitution in this template. + + +## PromptVariable + +A variable that can be substituted in a prompt template. + +Variables define named placeholders that can be replaced with actual values +during template processing. They can include metadata about expected types, +descriptions for user interfaces, and validation constraints. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + Default value to use if no value is provided. + + + Human-readable description of this variable. + + + The variable name (used in \{\{variable_name\}\} placeholders). + + + Whether this variable is required for template processing. + + - Default: `false` + + +PromptVariableType | null} > + The expected type of this variable's value. + + + The current value of the variable (if set). + + +## PromptVariableType + +The expected type of a prompt variable's value. + +This helps clients provide appropriate input interfaces and validation +for prompt variables. + +**Type:** Union + + + A string value (default if not specified). + + + + A numeric value (integer or float). + + + + A boolean value (true/false). + + + + A date/time value in ISO 8601 format. + + + + A URL or URI reference. + + + + An email address. + + + + A multiline text value. + + + +A value selected from a predefined list (enum-like). + + + + + + + ## ProtocolVersion @@ -6080,8 +6663,10 @@ This capability is not part of the spec yet, and may be removed or changed at an Capabilities for additional session directories support. -By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on -supported session lifecycle requests and `session/list`. +By supplying `\{\}` it means that the agent supports the `additionalDirectories` +field on supported session lifecycle requests. Agents that also support +`session/list` may return `SessionInfo.additionalDirectories` to report the +complete ordered additional-root list associated with a listed session. **Type:** Object @@ -6125,11 +6710,26 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte This capability is not part of the spec yet, and may be removed or changed at any point. -Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. +Whether the agent supports `additionalDirectories` on supported session lifecycle requests. + +Agents that also support `session/list` may return +`SessionInfo.additionalDirectories` to report the complete ordered +additional-root list associated with a listed session. SessionCloseCapabilities | null} > Whether the agent supports `session/close`. + +SessionDeleteCapabilities | null} > + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Whether the agent supports `session/delete`. + +Optional. Omitted or `null` both mean the agent does not advertise support. +Supplying `\{\}` means the agent supports deleting sessions from `session/list`. + SessionForkCapabilities | null} > **UNSTABLE** @@ -6394,6 +6994,29 @@ Unique identifier for a session configuration option value. **Type:** `string` +## SessionDeleteCapabilities + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Capabilities for the `session/delete` method. + +Supplying `\{\}` means the agent supports deleting sessions from `session/list`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ## SessionForkCapabilities **UNSTABLE** @@ -6449,9 +7072,11 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte This capability is not part of the spec yet, and may be removed or changed at any point. -Authoritative ordered additional workspace roots for this session. Each path must be absolute. +Additional workspace roots reported for this session. Each path must be absolute. -When omitted or empty, there are no additional roots for the session. +When present, this is the complete ordered additional-root list reported +by the Agent. Omitted and empty values are equivalent: the response +reports no additional roots. diff --git a/docs/protocol/draft/schema.mdx b/docs/protocol/draft/schema.mdx index b97b07c33..a60e3c514 100644 --- a/docs/protocol/draft/schema.mdx +++ b/docs/protocol/draft/schema.mdx @@ -3,6 +3,11 @@ title: "Schema" description: "Schema definitions for the Agent Client Protocol" --- + + The schema file can be downloaded directly from the [latest GitHub + release](https://github.com/agentclientprotocol/agent-client-protocol/releases/latest/download/schema.json). + + ## Agent Defines the interface that all ACP-compliant agents must implement. @@ -309,7 +314,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte AgentCapabilities} > Capabilities supported by the agent. - - Default: `{"auth":{},"loadSession":false,"mcpCapabilities":{"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false},"sessionCapabilities":{}}` + - Default: `{"auth":{},"loadSession":false,"mcpCapabilities":{"acp":false,"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false,"promptVariables":false},"sessionCapabilities":{}}` Implementation | null} > @@ -334,10 +339,6 @@ The client should disconnect, if it doesn't support this version. ### logout -**UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - Logs out of the current authenticated state. After a successful logout, all new sessions will require authentication. @@ -345,13 +346,59 @@ There is no guarantee about the behavior of already running sessions. #### LogoutRequest +Request parameters for the logout method. + +Terminates the current authenticated session. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + +#### LogoutResponse + +Response to the `logout` method. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + +### mcp/message + **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Request parameters for the logout method. +Exchanges an MCP-over-ACP message. -Terminates the current authenticated session. +#### MessageMcpNotification + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Notification parameters for `mcp/message`. + +This is used when the wrapped MCP message is a notification and the outer JSON-RPC +envelope has no `id`. **Type:** Object @@ -365,14 +412,26 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. -#### LogoutResponse +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpRequest **UNSTABLE** This capability is not part of the spec yet, and may be removed or changed at any point. -Response to the `logout` method. +Request parameters for `mcp/message`. **Type:** Object @@ -386,6 +445,28 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. + +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/message`. + +This is the inner MCP response result payload. Any JSON value is valid. ### nes/accept @@ -633,7 +714,7 @@ This capability is not part of the spec yet, and may be removed or changed at an Disables a provider. -#### DisableProvidersRequest +#### DisableProviderRequest **UNSTABLE** @@ -657,7 +738,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte Provider id to disable. -#### DisableProvidersResponse +#### DisableProviderResponse **UNSTABLE** @@ -741,7 +822,7 @@ This capability is not part of the spec yet, and may be removed or changed at an Replaces the configuration for a provider. -#### SetProvidersRequest +#### SetProviderRequest **UNSTABLE** @@ -777,7 +858,7 @@ May include authorization, routing, or other integration-specific headers. Provider id to configure. -#### SetProvidersResponse +#### SetProviderResponse **UNSTABLE** @@ -889,6 +970,64 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +### session/delete + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Deletes an existing session from `session/list`. + +This method is only available if the agent advertises the `sessionCapabilities.delete` capability. + +#### DeleteSessionRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for deleting an existing session from `session/list`. + +Only available if the Agent supports the `sessionCapabilities.delete` capability. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +SessionId} required> + The ID of the session to delete. + + +#### DeleteSessionResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response from deleting a session. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ### session/fork @@ -1018,17 +1157,6 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - -"string"[]} > - **UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - -Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - -This filter applies only when the field is present and non-empty. When -omitted or empty, no additional-root filter is applied. - Opaque cursor token from a previous response's nextCursor field for cursor-based pagination @@ -1105,7 +1233,8 @@ Additional workspace roots to activate for this session. Each path must be absol When omitted or empty, no additional roots are activated. When non-empty, this is the complete resulting additional-root list for the loaded -session. +session. It may differ from any previously used or reported list as long as +the request `cwd` matches the session's `cwd`. @@ -1398,7 +1527,8 @@ Additional workspace roots to activate for this session. Each path must be absol When omitted or empty, no additional roots are activated. When non-empty, this is the complete resulting additional-root list for the resumed -session. +session. It may differ from any previously used or reported list as long as +the request `cwd` matches the session's `cwd`. @@ -1948,6 +2078,205 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +### mcp/connect + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Opens an MCP-over-ACP connection. + +#### ConnectMcpRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for `mcp/connect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpServerAcpId} required> + The ACP MCP server ID that was provided by the component declaring the MCP server. + + +#### ConnectMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/connect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The unique identifier for this MCP-over-ACP connection. + + + +### mcp/disconnect + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Closes an MCP-over-ACP connection. + +#### DisconnectMcpRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for `mcp/disconnect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The MCP-over-ACP connection to close. + + +#### DisconnectMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/disconnect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + +### mcp/message + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Exchanges an MCP-over-ACP message. + +#### MessageMcpNotification + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Notification parameters for `mcp/message`. + +This is used when the wrapped MCP message is a notification and the outer JSON-RPC +envelope has no `id`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. + +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpRequest + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Request parameters for `mcp/message`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpConnectionId} required> + The MCP-over-ACP connection this message is sent on. + + + The inner MCP method name. + + + Optional inner MCP params. + +If omitted or set to `null`, the inner MCP message has no params. + + + +#### MessageMcpResponse + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Response to `mcp/message`. + +This is the inner MCP response result payload. Any JSON value is valid. + ### session/request_permission @@ -2426,10 +2755,6 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte ## AgentAuthCapabilities -**UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - Authentication-related capabilities supported by the agent. **Type:** Object @@ -2473,11 +2798,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte AgentAuthCapabilities} > - **UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - -Authentication-related capabilities supported by the agent. + Authentication-related capabilities supported by the agent. - Default: `{}` @@ -2491,7 +2812,7 @@ Authentication-related capabilities supported by the agent. McpCapabilities} > MCP capabilities supported by the agent. - - Default: `{"http":false,"sse":false}` + - Default: `{"acp":false,"http":false,"sse":false}` NesCapabilities | null} > @@ -2513,7 +2834,7 @@ The position encoding selected by the agent from the client's supported encoding PromptCapabilities} > Prompt capabilities supported by the agent. - - Default: `{"audio":false,"embeddedContext":false,"image":false}` + - Default: `{"audio":false,"embeddedContext":false,"image":false,"promptVariables":false}` ProvidersCapabilities | null} > @@ -3290,6 +3611,40 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +A template that supports variable substitution using \{\{variable_name\}\} syntax. + +Allows dynamic content generation by substituting variables into template strings. +Variables are resolved at processing time and can include values from context, +user input, or system state. + +Requires the `promptVariables` prompt capability when included in prompts. + + + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +Annotations | null} > + + + The template string with \{\{variable_name\}\} placeholders. + + + The discriminator value. Must be `"prompt_template"`. + +PromptVariable[]} required> + Variables available for substitution in this template. + + + + + ## ContentChunk A streamed item of content @@ -4331,10 +4686,6 @@ Protocol names that do not begin with `_` are reserved for the ACP spec. ## LogoutCapabilities -**UNSTABLE** - -This capability is not part of the spec yet, and may be removed or changed at any point. - Logout capabilities supported by the agent. By supplying `\{\}` it means that the agent supports the logout method. @@ -4367,6 +4718,16 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Agent supports `McpServer::Acp`. + + - Default: `false` + Agent supports `McpServer::Http`. @@ -4381,6 +4742,16 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte +## McpConnectionId + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +A unique identifier for an active MCP-over-ACP connection. + +**Type:** `string` + ## McpServer Configuration for connecting to an MCP (Model Context Protocol) server. @@ -4454,6 +4825,43 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +ACP transport configuration + +Only available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`. +The MCP server is provided by an ACP component and communicates over the ACP channel. + + + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpServerAcpId} required> + Unique identifier for this MCP server, generated by the component providing it. + +Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible +on the same ACP connection. + + + + Human-readable name identifying this MCP server. + + + The discriminator value. Must be `"acp"`. + + + + + Stdio transport configuration @@ -4485,6 +4893,54 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte +## McpServerAcp + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +ACP transport configuration for MCP. + +The MCP server is provided by an ACP component and communicates over the ACP channel +using `mcp/connect`, `mcp/message`, and `mcp/disconnect`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +McpServerAcpId} required> + Unique identifier for this MCP server, generated by the component providing it. + +Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible +on the same ACP connection. + + + + Human-readable name identifying this MCP server. + + +## McpServerAcpId + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Unique identifier for an MCP server using the ACP transport. + +The value is opaque and generated by the ACP component providing the MCP server. It is +used by `mcp/connect` to route connection requests back to the component that declared the +server. + +**Type:** `string` + ## McpServerHttp HTTP transport configuration for MCP. @@ -5826,6 +6282,133 @@ in prompt requests for pieces of context that are referenced in the message. - Default: `false` + + Agent supports prompt variables and templates in `session/prompt` requests. + +When enabled, the Client is allowed to include `ContentBlock::PromptTemplate` +in prompt requests with variable substitution support. + + - Default: `false` + + + +## PromptTemplateContent + +A template content block that supports variable substitution. + +Templates use \{\{variable_name\}\} syntax for variable placeholders that can be +substituted with actual values at processing time. This enables dynamic content +generation and reusable prompt templates. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +Annotations | null} > + + + The template string with \{\{variable_name\}\} placeholders. + +PromptVariable[]} required> + Variables available for substitution in this template. + + +## PromptVariable + +A variable that can be substituted in a prompt template. + +Variables define named placeholders that can be replaced with actual values +during template processing. They can include metadata about expected types, +descriptions for user interfaces, and validation constraints. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + Default value to use if no value is provided. + + + Human-readable description of this variable. + + + The variable name (used in \{\{variable_name\}\} placeholders). + + + Whether this variable is required for template processing. + + - Default: `false` + + +PromptVariableType | null} > + The expected type of this variable's value. + + + The current value of the variable (if set). + + +## PromptVariableType + +The expected type of a prompt variable's value. + +This helps clients provide appropriate input interfaces and validation +for prompt variables. + +**Type:** Union + + + A string value (default if not specified). + + + + A numeric value (integer or float). + + + + A boolean value (true/false). + + + + A date/time value in ISO 8601 format. + + + + A URL or URI reference. + + + + An email address. + + + + A multiline text value. + + + +A value selected from a predefined list (enum-like). + + + + + + + ## ProtocolVersion @@ -6080,8 +6663,10 @@ This capability is not part of the spec yet, and may be removed or changed at an Capabilities for additional session directories support. -By supplying `\{\}` it means that the agent supports the `additionalDirectories` field on -supported session lifecycle requests and `session/list`. +By supplying `\{\}` it means that the agent supports the `additionalDirectories` +field on supported session lifecycle requests. Agents that also support +`session/list` may return `SessionInfo.additionalDirectories` to report the +complete ordered additional-root list associated with a listed session. **Type:** Object @@ -6125,11 +6710,26 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte This capability is not part of the spec yet, and may be removed or changed at any point. -Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. +Whether the agent supports `additionalDirectories` on supported session lifecycle requests. + +Agents that also support `session/list` may return +`SessionInfo.additionalDirectories` to report the complete ordered +additional-root list associated with a listed session. SessionCloseCapabilities | null} > Whether the agent supports `session/close`. + +SessionDeleteCapabilities | null} > + **UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Whether the agent supports `session/delete`. + +Optional. Omitted or `null` both mean the agent does not advertise support. +Supplying `\{\}` means the agent supports deleting sessions from `session/list`. + SessionForkCapabilities | null} > **UNSTABLE** @@ -6394,6 +6994,29 @@ Unique identifier for a session configuration option value. **Type:** `string` +## SessionDeleteCapabilities + +**UNSTABLE** + +This capability is not part of the spec yet, and may be removed or changed at any point. + +Capabilities for the `session/delete` method. + +Supplying `\{\}` means the agent supports deleting sessions from `session/list`. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ## SessionForkCapabilities **UNSTABLE** @@ -6449,9 +7072,11 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte This capability is not part of the spec yet, and may be removed or changed at any point. -Authoritative ordered additional workspace roots for this session. Each path must be absolute. +Additional workspace roots reported for this session. Each path must be absolute. -When omitted or empty, there are no additional roots for the session. +When present, this is the complete ordered additional-root list reported +by the Agent. Omitted and empty values are equivalent: the response +reports no additional roots. diff --git a/docs/protocol/draft/session-config-options.mdx b/docs/protocol/draft/session-config-options.mdx new file mode 100644 index 000000000..524b489fe --- /dev/null +++ b/docs/protocol/draft/session-config-options.mdx @@ -0,0 +1,282 @@ +--- +title: "Session Config Options" +description: "Flexible configuration selectors for agent sessions" +--- + +Agents can provide an arbitrary list of configuration options for a session, allowing Clients to offer users customizable selectors for things like models, modes, reasoning levels, and more. + + + Session Config Options are the preferred way to expose session-level + configuration. If an Agent provides `configOptions`, Clients **SHOULD** use + them instead of the [`modes`](./session-modes) field. Modes will be removed in + a future version of the protocol. + + +## Initial State + +During [Session Setup](./session-setup) the Agent **MAY** return a list of configuration options and their current values: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "sessionId": "sess_abc123def456", + "configOptions": [ + { + "id": "mode", + "name": "Session Mode", + "description": "Controls how the agent requests permission", + "category": "mode", + "type": "select", + "currentValue": "ask", + "options": [ + { + "value": "ask", + "name": "Ask", + "description": "Request permission before making any changes" + }, + { + "value": "code", + "name": "Code", + "description": "Write and modify code with full tool access" + } + ] + }, + { + "id": "model", + "name": "Model", + "category": "model", + "type": "select", + "currentValue": "model-1", + "options": [ + { + "value": "model-1", + "name": "Model 1", + "description": "The fastest model" + }, + { + "value": "model-2", + "name": "Model 2", + "description": "The most powerful model" + } + ] + } + ] + } +} +``` + + + The list of configuration options available for this session. The order of + this array represents the Agent's preferred priority. Clients **SHOULD** + respect this ordering when displaying options. + + +### ConfigOption + + + Unique identifier for this configuration option. Used when setting values. + + + + Human-readable label for the option + + + + Optional description providing more details about what this option controls + + + + Optional [semantic category](#option-categories) to help Clients provide + consistent UX. + + + + The type of input control. Currently only `select` is supported. + + + + The currently selected value for this option + + + + The available values for this option + + +### ConfigOptionValue + + + The value identifier used when setting this option + + + + Human-readable name to display + + + + Optional description of what this value does + + +## Option Categories + +Each config option **MAY** include a `category` field. Categories are semantic metadata intended to help Clients provide consistent UX, such as attaching keyboard shortcuts, choosing icons, or deciding placement. + + + Categories are for UX purposes only and **MUST NOT** be required for + correctness. Clients **MUST** handle missing or unknown categories gracefully. + + +Category names beginning with `_` are free for custom use (e.g., `_my_custom_category`). Category names that do not begin with `_` are reserved for the ACP spec. + +| Category | Description | +| --------------- | -------------------------------- | +| `mode` | Session mode selector | +| `model` | Model selector | +| `thought_level` | Thought/reasoning level selector | + +When multiple options share the same category, Clients **SHOULD** use the array ordering to resolve ties, preferring earlier options in the list for prominent placement or keyboard shortcuts. + +## Option Ordering + +The order of the `configOptions` array is significant. Agents **SHOULD** place higher-priority options first in the list. + +Clients **SHOULD**: + +- Display options in the order provided by the Agent +- Use ordering to resolve ties when multiple options share the same category +- If displaying a limited number of options, prefer those at the beginning of the list + +## Default Values and Graceful Degradation + +Agents **MUST** always provide a default value for every configuration option. This ensures the Agent can operate correctly even if: + +- The Client doesn't support configuration options +- The Client chooses not to display certain options +- The Client receives an option type it doesn't recognize + +If a Client receives an option with an unrecognized `type`, it **SHOULD** ignore that option. The Agent will continue using its default value. + +## Setting a Config Option + +The current value of a config option can be changed at any point during a session, whether the Agent is idle or generating a response. + +### From the Client + +Clients can change a config option value by calling the `session/set_config_option` method: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/set_config_option", + "params": { + "sessionId": "sess_abc123def456", + "configId": "mode", + "value": "code" + } +} +``` + + + The ID of the session + + + + The `id` of the configuration option to change + + + + The new value to set. Must be one of the values listed in the option's + `options` array. + + +The Agent **MUST** respond with the complete list of all configuration options and their current values: + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "result": { + "configOptions": [ + { + "id": "mode", + "name": "Session Mode", + "type": "select", + "currentValue": "code", + "options": [...] + }, + { + "id": "model", + "name": "Model", + "type": "select", + "currentValue": "model-1", + "options": [...] + } + ] + } +} +``` + + + The response always contains the **complete** configuration state. This allows + Agents to reflect dependent changes. For example, if changing the model + affects available reasoning options, or if an option's available values change + based on another selection. + + +### From the Agent + +The Agent can also change configuration options and notify the Client by sending a `config_option_update` session notification: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "config_option_update", + "configOptions": [ + { + "id": "mode", + "name": "Session Mode", + "type": "select", + "currentValue": "code", + "options": [...] + }, + { + "id": "model", + "name": "Model", + "type": "select", + "currentValue": "model-2", + "options": [...] + } + ] + } + } +} +``` + +This notification also contains the complete configuration state. Common reasons an Agent might update configuration options include: + +- Switching modes after completing a planning phase +- Falling back to a different model due to rate limits or errors +- Adjusting available options based on context discovered during execution + +## Relationship to Session Modes + +Session Config Options supersede the older [Session Modes](./session-modes) API. However, during the transition period, Agents that provide mode-like configuration **SHOULD** send both: + +- `configOptions` with a `category: "mode"` option for Clients that support config options +- `modes` for Clients that only support the older API + +If an Agent provides both `configOptions` and `modes` in the session response: + +- Clients that support config options **SHOULD** use `configOptions` exclusively and ignore `modes` +- Clients that don't support config options **SHOULD** fall back to `modes` +- Agents **SHOULD** keep both in sync to ensure consistent behavior regardless of which field the Client uses + + + Learn about the Session Modes API + diff --git a/docs/protocol/draft/session-delete.mdx b/docs/protocol/draft/session-delete.mdx new file mode 100644 index 000000000..f07da9e6a --- /dev/null +++ b/docs/protocol/draft/session-delete.mdx @@ -0,0 +1,90 @@ +--- +title: "Session Delete" +description: "Removing sessions from session history" +--- + +The `session/delete` method allows Clients to remove sessions from an Agent's `session/list` results. This gives users a standard way to manage session history across ACP Clients and Agents. + +Before deleting sessions, Clients **MUST** first complete the [initialization](/protocol/initialization) phase and verify the Agent supports this capability. + +
+ +```mermaid +sequenceDiagram + participant Client + participant Agent + + Note over Agent,Client: Initialized + + Client->>Agent: session/list + Agent-->>Client: session/list response (sessions) + + alt User deletes a session + Client->>Agent: session/delete (sessionId) + Agent-->>Client: session/delete response + end + + Client->>Agent: session/list + Agent-->>Client: session/list response (without deleted session) +``` + +
+ +## Checking Support + +Before attempting to delete a session, Clients **MUST** verify that the Agent supports this capability by checking the unstable `sessionCapabilities.delete` field in the `initialize` response: + +```json highlight={7-9} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "agentCapabilities": { + "sessionCapabilities": { + "delete": {} + } + } + } +} +``` + +If `sessionCapabilities.delete` is omitted or `null`, the Agent does not support deleting sessions and Clients **MUST NOT** attempt to call `session/delete`. Supplying `{}` means the Agent supports the method. + +## Deleting a Session + +Clients delete a session by calling `session/delete` with the session ID to remove from session history: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "session/delete", + "params": { + "sessionId": "sess_abc123def456" + } +} +``` + + + Unique identifier for the session to delete. + + +On success, the Agent returns an empty result: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "result": {} +} +``` + +## Semantics + +- Agents **MUST NOT** accept `session/delete` calls unless they advertised `sessionCapabilities.delete` during initialization. +- Deleted sessions no longer appear in future `session/list` results. +- Deleting an already-deleted session, or a session that never existed, **SHOULD** succeed silently. +- Agents may implement soft delete or hard delete. ACP only specifies the user-facing session-list behavior. +- Behavior for `session/load` on a deleted session is implementation-defined. +- Behavior for deleting an active session is implementation-defined. diff --git a/docs/protocol/draft/session-list.mdx b/docs/protocol/draft/session-list.mdx index 8e1be7908..6f9e5701a 100644 --- a/docs/protocol/draft/session-list.mdx +++ b/docs/protocol/draft/session-list.mdx @@ -55,10 +55,15 @@ If `sessionCapabilities.list` is not present, the Agent does not support listing If the Agent also advertises the unstable - `sessionCapabilities.additionalDirectories` capability, `session/list` - supports filtering by `additionalDirectories`, and any returned - `SessionInfo.additionalDirectories` value is the authoritative additional-root - list for that session. + `sessionCapabilities.additionalDirectories` capability, returned `SessionInfo` + objects may include `additionalDirectories` to report additional workspace + roots for listed sessions. + + + + If the Agent advertises the unstable `sessionCapabilities.delete` capability, + Clients can remove sessions from future `session/list` results with + [`session/delete`](/protocol/draft/session-delete). ## Listing Sessions @@ -84,13 +89,6 @@ All parameters are optional. A request with an empty `params` object returns the with a matching `cwd` are returned. - - If the Agent advertises `sessionCapabilities.additionalDirectories`, filter - sessions by the exact ordered additional-root list when this field is present - and non-empty. Omitting the field or providing an empty array means no - additional-root filter is applied. - - Opaque cursor token from a previous response's `nextCursor` field for cursor-based pagination. See [Pagination](#pagination). @@ -142,10 +140,12 @@ The Agent **MUST** respond with a list of sessions and optional pagination metad Working directory for the session. Always an absolute path.
- If the Agent advertises `sessionCapabilities.additionalDirectories`, this - is the authoritative ordered additional-root list for the session when - present. Omitting the field or returning an empty array means there are no - additional roots. + If the Agent advertises `sessionCapabilities.additionalDirectories`, it + MAY include this field to report the complete ordered additional-root list + associated with the listed session. Omitted and empty values are + equivalent: this `SessionInfo` response reports no additional roots. + Clients MUST NOT merge this field with prior values or infer additional + roots from agent-specific state. diff --git a/docs/protocol/draft/session-modes.mdx b/docs/protocol/draft/session-modes.mdx new file mode 100644 index 000000000..03bdaa170 --- /dev/null +++ b/docs/protocol/draft/session-modes.mdx @@ -0,0 +1,173 @@ +--- +title: "Session Modes" +description: "Switch between different agent operating modes" +--- + + + You can now use [Session Config Options](./session-config-options). Dedicated + session mode methods will be removed in a future version of the protocol. + Until then, you can offer both to clients for backwards compatibility. + + +Agents can provide a set of modes they can operate in. Modes often affect the system prompts used, the availability of tools, and whether they request permission before running. + +## Initial state + +During [Session Setup](./session-setup) the Agent **MAY** return a list of modes it can operate in and the currently active mode: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "sessionId": "sess_abc123def456", + "modes": { + "currentModeId": "ask", + "availableModes": [ + { + "id": "ask", + "name": "Ask", + "description": "Request permission before making any changes" + }, + { + "id": "architect", + "name": "Architect", + "description": "Design and plan software systems without implementation" + }, + { + "id": "code", + "name": "Code", + "description": "Write and modify code with full tool access" + } + ] + } + } +} +``` + + + The current mode state for the session + + +### SessionModeState + + + The ID of the mode that is currently active + + + + The set of modes that the Agent can operate in + + +### SessionMode + + + Unique identifier for this mode + + + + Human-readable name of the mode + + + + Optional description providing more details about what this mode does + + +## Setting the current mode + +The current mode can be changed at any point during a session, whether the Agent is idle or generating a response. + +### From the Client + +Typically, Clients display the available modes to the user and allow them to change the current one, which they can do by calling the [`session/set_mode`](./schema#session%2Fset-mode) method. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "method": "session/set_mode", + "params": { + "sessionId": "sess_abc123def456", + "modeId": "code" + } +} +``` + + + The ID of the session to set the mode for + + + + The ID of the mode to switch to. Must be one of the modes listed in + `availableModes` + + +### From the Agent + +The Agent can also change its own mode and let the Client know by sending the `current_mode_update` session notification: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "current_mode_update", + "modeId": "code" + } + } +} +``` + +#### Exiting plan modes + +A common case where an Agent might switch modes is from within a special "exit mode" tool that can be provided to the language model during plan/architect modes. The language model can call this tool when it determines it's ready to start implementing a solution. + +This "switch mode" tool will usually request permission before running, which it can do just like any other tool: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "session/request_permission", + "params": { + "sessionId": "sess_abc123def456", + "toolCall": { + "toolCallId": "call_switch_mode_001", + "title": "Ready for implementation", + "kind": "switch_mode", + "status": "pending", + "content": [ + { + "type": "text", + "text": "## Implementation Plan..." + } + ] + }, + "options": [ + { + "optionId": "code", + "name": "Yes, and auto-accept all actions", + "kind": "allow_always" + }, + { + "optionId": "ask", + "name": "Yes, and manually accept actions", + "kind": "allow_once" + }, + { + "optionId": "reject", + "name": "No, stay in architect mode", + "kind": "reject_once" + } + ] + } +} +``` + +When an option is chosen, the tool runs, setting the mode and sending the `current_mode_update` notification mentioned above. + + + Learn more about permission requests + diff --git a/docs/protocol/draft/session-setup.mdx b/docs/protocol/draft/session-setup.mdx index f3d9fbb66..265558a58 100644 --- a/docs/protocol/draft/session-setup.mdx +++ b/docs/protocol/draft/session-setup.mdx @@ -7,6 +7,8 @@ Sessions represent a specific conversation or thread between the [Client](/proto Before creating a session, Clients **MUST** first complete the [initialization](/protocol/initialization) phase to establish protocol compatibility and capabilities. +If the Agent requires authentication, `session/new` may fail with an `auth_required` error until the Client completes the [authentication flow](/protocol/draft/authentication). +
```mermaid @@ -365,7 +367,7 @@ When present, `additionalDirectories` has the following behavior: - `cwd` remains the primary working directory and the base for relative paths - each `additionalDirectories` entry **MUST** be an absolute path - omitting the field or providing an empty array activates no additional roots for the resulting session -- on `session/load` and `session/resume`, Clients must send the full intended additional-root list again because omitting the field or providing an empty array does not restore stored roots implicitly +- on `session/load` and `session/resume`, Clients must send the full intended additional-root list again; that list may differ from any previous or reported list as long as the request `cwd` matches the session's `cwd`, and omitting the field or providing an empty array does not restore stored roots implicitly ## Session ID diff --git a/docs/protocol/draft/slash-commands.mdx b/docs/protocol/draft/slash-commands.mdx new file mode 100644 index 000000000..271b115dd --- /dev/null +++ b/docs/protocol/draft/slash-commands.mdx @@ -0,0 +1,96 @@ +--- +title: "Slash Commands" +description: "Advertise available slash commands to clients" +--- + +Agents can advertise a set of slash commands that users can invoke. These commands provide quick access to specific agent capabilities and workflows. Commands are run as part of regular [prompt](./prompt-turn) requests where the Client includes the command text in the prompt. + +## Advertising commands + +After creating a session, the Agent **MAY** send a list of available commands via the `available_commands_update` session notification: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "available_commands_update", + "availableCommands": [ + { + "name": "web", + "description": "Search the web for information", + "input": { + "hint": "query to search for" + } + }, + { + "name": "test", + "description": "Run tests for the current project" + }, + { + "name": "plan", + "description": "Create a detailed implementation plan", + "input": { + "hint": "description of what to plan" + } + } + ] + } + } +} +``` + + + The list of commands available in this session + + +### AvailableCommand + + + The command name (e.g., "web", "test", "plan") + + + + Human-readable description of what the command does + + + + Optional input specification for the command + + +### AvailableCommandInput + +Currently supports unstructured text input: + + + A hint to display when the input hasn't been provided yet + + +## Dynamic updates + +The Agent can update the list of available commands at any time during a session by sending another `available_commands_update` notification. This allows commands to be added based on context, removed when no longer relevant, or modified with updated descriptions. + +## Running commands + +Commands are included as regular user messages in prompt requests: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "session/prompt", + "params": { + "sessionId": "sess_abc123def456", + "prompt": [ + { + "type": "text", + "text": "/web agent client protocol" + } + ] + } +} +``` + +The Agent recognizes the command prefix and processes it accordingly. Commands may be accompanied by any other user message content types (images, audio, etc.) in the same prompt array. diff --git a/docs/protocol/draft/terminals.mdx b/docs/protocol/draft/terminals.mdx new file mode 100644 index 000000000..270ec7588 --- /dev/null +++ b/docs/protocol/draft/terminals.mdx @@ -0,0 +1,281 @@ +--- +title: "Terminals" +description: "Executing and managing terminal commands" +--- + +The terminal methods allow Agents to execute shell commands within the Client's environment. These methods enable Agents to run build processes, execute scripts, and interact with command-line tools while providing real-time output streaming and process control. + +## Checking Support + +Before attempting to use terminal methods, Agents **MUST** verify that the Client supports this capability by checking the [Client Capabilities](./initialization#client-capabilities) field in the `initialize` response: + +```json highlight={7} +{ + "jsonrpc": "2.0", + "id": 0, + "result": { + "protocolVersion": 1, + "clientCapabilities": { + "terminal": true + } + } +} +``` + +If `terminal` is `false` or not present, the Agent **MUST NOT** attempt to call any terminal methods. + +## Executing Commands + +The `terminal/create` method starts a command in a new terminal: + +```json +{ + "jsonrpc": "2.0", + "id": 5, + "method": "terminal/create", + "params": { + "sessionId": "sess_abc123def456", + "command": "npm", + "args": ["test", "--coverage"], + "env": [ + { + "name": "NODE_ENV", + "value": "test" + } + ], + "cwd": "/home/user/project", + "outputByteLimit": 1048576 + } +} +``` + + + The [Session ID](./session-setup#session-id) for this request + + + + The command to execute + + + + Array of command arguments + + + + Environment variables for the command. + +Each variable has: + +- `name`: The environment variable name +- `value`: The environment variable value + + + + + Working directory for the command (absolute path) + + + + Maximum number of output bytes to retain. Once exceeded, earlier output is + truncated to stay within this limit. + +When the limit is exceeded, the Client truncates from the beginning of the output +to stay within the limit. + +The Client **MUST** ensure truncation happens at a character boundary to maintain valid +string output, even if this means the retained output is slightly less than the +specified limit. + + + +The Client returns a Terminal ID immediately without waiting for completion: + +```json +{ + "jsonrpc": "2.0", + "id": 5, + "result": { + "terminalId": "term_xyz789" + } +} +``` + +This allows the command to run in the background while the Agent performs other operations. + +After creating the terminal, the Agent can use the `terminal/wait_for_exit` method to wait for the command to complete. + + + The Agent **MUST** release the terminal using `terminal/release` when it's no + longer needed. + + +## Embedding in Tool Calls + +Terminals can be embedded directly in [tool calls](./tool-calls) to provide real-time output to users: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "tool_call", + "toolCallId": "call_002", + "title": "Running tests", + "kind": "execute", + "status": "in_progress", + "content": [ + { + "type": "terminal", + "terminalId": "term_xyz789" + } + ] + } + } +} +``` + +When a terminal is embedded in a tool call, the Client displays live output as it's generated and continues to display it even after the terminal is released. + +## Getting Output + +The `terminal/output` method retrieves the current terminal output without waiting for the command to complete: + +```json +{ + "jsonrpc": "2.0", + "id": 6, + "method": "terminal/output", + "params": { + "sessionId": "sess_abc123def456", + "terminalId": "term_xyz789" + } +} +``` + +The Client responds with the current output and exit status (if the command has finished): + +```json +{ + "jsonrpc": "2.0", + "id": 6, + "result": { + "output": "Running tests...\n✓ All tests passed (42 total)\n", + "truncated": false, + "exitStatus": { + "exitCode": 0, + "signal": null + } + } +} +``` + + + The terminal output captured so far + + + + Whether the output was truncated due to byte limits + + + + Present only if the command has exited. Contains: + +- `exitCode`: The process exit code (may be null) +- `signal`: The signal that terminated the process (may be null) + + + +## Waiting for Exit + +The `terminal/wait_for_exit` method returns once the command completes: + +```json +{ + "jsonrpc": "2.0", + "id": 7, + "method": "terminal/wait_for_exit", + "params": { + "sessionId": "sess_abc123def456", + "terminalId": "term_xyz789" + } +} +``` + +The Client responds once the command exits: + +```json +{ + "jsonrpc": "2.0", + "id": 7, + "result": { + "exitCode": 0, + "signal": null + } +} +``` + + + The process exit code (may be null if terminated by signal) + + + + The signal that terminated the process (may be null if exited normally) + + +## Killing Commands + +The `terminal/kill` method terminates a command without releasing the terminal: + +```json +{ + "jsonrpc": "2.0", + "id": 8, + "method": "terminal/kill", + "params": { + "sessionId": "sess_abc123def456", + "terminalId": "term_xyz789" + } +} +``` + +After killing a command, the terminal remains valid and can be used with: + +- `terminal/output` to get the final output +- `terminal/wait_for_exit` to get the exit status + +The Agent **MUST** still call `terminal/release` when it's done using it. + +### Building a Timeout + +Agents can implement command timeouts by combining terminal methods: + +1. Create a terminal with `terminal/create` +2. Start a timer for the desired timeout duration +3. Concurrently wait for either the timer to expire or `terminal/wait_for_exit` to return +4. If the timer expires first: + - Call `terminal/kill` to terminate the command + - Call `terminal/output` to retrieve any final output + - Include the output in the response to the model +5. Call `terminal/release` when done + +## Releasing Terminals + +The `terminal/release` kills the command if still running and releases all resources: + +```json +{ + "jsonrpc": "2.0", + "id": 9, + "method": "terminal/release", + "params": { + "sessionId": "sess_abc123def456", + "terminalId": "term_xyz789" + } +} +``` + +After release the terminal ID becomes invalid for all other `terminal/*` methods. + +If the terminal was added to a tool call, the client **SHOULD** continue to display its output after release. diff --git a/docs/protocol/draft/tool-calls.mdx b/docs/protocol/draft/tool-calls.mdx new file mode 100644 index 000000000..2982296a9 --- /dev/null +++ b/docs/protocol/draft/tool-calls.mdx @@ -0,0 +1,310 @@ +--- +title: "Tool Calls" +description: "How Agents report tool call execution" +--- + +Tool calls represent actions that language models request Agents to perform during a [prompt turn](./prompt-turn). When an LLM determines it needs to interact with external systems—like reading files, running code, or fetching data—it generates tool calls that the Agent executes on its behalf. + +Agents report tool calls through [`session/update`](./prompt-turn#3-agent-reports-output) notifications, allowing Clients to display real-time progress and results to users. + +While Agents handle the actual execution, they may leverage Client capabilities like [permission requests](#requesting-permission) or [file system access](./file-system) to provide a richer, more integrated experience. + +## Creating + +When the language model requests a tool invocation, the Agent **SHOULD** report it to the Client: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "tool_call", + "toolCallId": "call_001", + "title": "Reading configuration file", + "kind": "read", + "status": "pending" + } + } +} +``` + + + A unique identifier for this tool call within the session + + + + A human-readable title describing what the tool is doing + + + + The category of tool being invoked. + + + - `read` - Reading files or data - `edit` - Modifying files or content - + `delete` - Removing files or data - `move` - Moving or renaming files - + `search` - Searching for information - `execute` - Running commands or code - + `think` - Internal reasoning or planning - `fetch` - Retrieving external data + - `other` - Other tool types (default) + + +Tool kinds help Clients choose appropriate icons and optimize how they display tool execution progress. + + + + + The current [execution status](#status) (defaults to `pending`) + + + + [Content produced](#content) by the tool call + + + + [File locations](#following-the-agent) affected by this tool call + + + + The raw input parameters sent to the tool + + + + The raw output returned by the tool + + +## Updating + +As tools execute, Agents send updates to report progress and results. + +Updates use the `session/update` notification with `tool_call_update`: + +```json +{ + "jsonrpc": "2.0", + "method": "session/update", + "params": { + "sessionId": "sess_abc123def456", + "update": { + "sessionUpdate": "tool_call_update", + "toolCallId": "call_001", + "status": "in_progress", + "content": [ + { + "type": "content", + "content": { + "type": "text", + "text": "Found 3 configuration files..." + } + } + ] + } + } +} +``` + +All fields except `toolCallId` are optional in updates. Only the fields being changed need to be included. + +## Requesting Permission + +The Agent **MAY** request permission from the user before executing a tool call by calling the `session/request_permission` method: + +```json +{ + "jsonrpc": "2.0", + "id": 5, + "method": "session/request_permission", + "params": { + "sessionId": "sess_abc123def456", + "toolCall": { + "toolCallId": "call_001" + }, + "options": [ + { + "optionId": "allow-once", + "name": "Allow once", + "kind": "allow_once" + }, + { + "optionId": "reject-once", + "name": "Reject", + "kind": "reject_once" + } + ] + } +} +``` + + + The session ID for this request + + + + The tool call update containing details about the operation + + + + Available [permission options](#permission-options) for the user to choose + from + + +The Client responds with the user's decision: + +```json +{ + "jsonrpc": "2.0", + "id": 5, + "result": { + "outcome": { + "outcome": "selected", + "optionId": "allow-once" + } + } +} +``` + +Clients **MAY** automatically allow or reject permission requests according to the user settings. + +If the current prompt turn gets [cancelled](./prompt-turn#cancellation), the Client **MUST** respond with the `"cancelled"` outcome: + +```json +{ + "jsonrpc": "2.0", + "id": 5, + "result": { + "outcome": { + "outcome": "cancelled" + } + } +} +``` + + + The user's decision, either: - `cancelled` - The [prompt turn was + cancelled](./prompt-turn#cancellation) - `selected` with an `optionId` - The + ID of the selected permission option + + +### Permission Options + +Each permission option provided to the Client contains: + + + Unique identifier for this option + + + + Human-readable label to display to the user + + + + A hint to help Clients choose appropriate icons and UI treatment for each option. + +- `allow_once` - Allow this operation only this time +- `allow_always` - Allow this operation and remember the choice +- `reject_once` - Reject this operation only this time +- `reject_always` - Reject this operation and remember the choice + + + +## Status + +Tool calls progress through different statuses during their lifecycle: + + + The tool call hasn't started running yet because the input is either streaming + or awaiting approval + + + + The tool call is currently running + + + + The tool call completed successfully + + +The tool call failed with an error + +## Content + +Tool calls can produce different types of content: + +### Regular Content + +Standard [content blocks](./content) like text, images, or resources: + +```json +{ + "type": "content", + "content": { + "type": "text", + "text": "Analysis complete. Found 3 issues." + } +} +``` + +### Diffs + +File modifications shown as diffs: + +```json +{ + "type": "diff", + "path": "/home/user/project/src/config.json", + "oldText": "{\n \"debug\": false\n}", + "newText": "{\n \"debug\": true\n}" +} +``` + + + The absolute file path being modified + + + + The original content (null for new files) + + + + The new content after modification + + +### Terminals + +Live terminal output from command execution: + +```json +{ + "type": "terminal", + "terminalId": "term_xyz789" +} +``` + + + The ID of a terminal created with `terminal/create` + + +When a terminal is embedded in a tool call, the Client displays live output as it's generated and continues to display it even after the terminal is released. + + + Learn more about Terminals + + +## Following the Agent + +Tool calls can report file locations they're working with, enabling Clients to implement "follow-along" features that track which files the Agent is accessing or modifying in real-time. + +```json +{ + "path": "/home/user/project/src/main.py", + "line": 42 +} +``` + + + The absolute file path being accessed or modified + + + + Optional line number within the file + diff --git a/docs/protocol/draft/transports.mdx b/docs/protocol/draft/transports.mdx new file mode 100644 index 000000000..274fdbdbb --- /dev/null +++ b/docs/protocol/draft/transports.mdx @@ -0,0 +1,52 @@ +--- +title: "Transports" +description: "Mechanisms for agents and clients to communicate with each other" +--- + +ACP uses JSON-RPC to encode messages. JSON-RPC messages **MUST** be UTF-8 encoded. + +The protocol currently defines the following transport mechanisms for agent-client communication: + +1. [stdio](#stdio), communication over standard in and standard out +2. _[Streamable HTTP](#streamable-http) (draft proposal in progress)_ + +Agents and clients **SHOULD** support stdio whenever possible. + +It is also possible for agents and clients to implement [custom transports](#custom-transports). + +## stdio + +In the **stdio** transport: + +- The client launches the agent as a subprocess. +- The agent reads JSON-RPC messages from its standard input (`stdin`) and sends messages to its standard output (`stdout`). +- Messages are individual JSON-RPC requests, notifications, or responses. +- Messages are delimited by newlines (`\n`), and **MUST NOT** contain embedded newlines. +- The agent **MAY** write UTF-8 strings to its standard error (`stderr`) for logging purposes. Clients **MAY** capture, forward, or ignore this logging. +- The agent **MUST NOT** write anything to its `stdout` that is not a valid ACP message. +- The client **MUST NOT** write anything to the agent's `stdin` that is not a valid ACP message. + +```mermaid +sequenceDiagram + participant Client + participant Agent Process + + Client->>+Agent Process: Launch subprocess + loop Message Exchange + Client->>Agent Process: Write to stdin + Agent Process->>Client: Write to stdout + Agent Process--)Client: Optional logs on stderr + end + Client->>Agent Process: Close stdin, terminate subprocess + deactivate Agent Process +``` + +## _Streamable HTTP_ + +_In discussion, draft proposal in progress._ + +## Custom Transports + +Agents and clients **MAY** implement additional custom transport mechanisms to suit their specific needs. The protocol is transport-agnostic and can be implemented over any communication channel that supports bidirectional message exchange. + +Implementers who choose to support custom transports **MUST** ensure they preserve the JSON-RPC message format and lifecycle requirements defined by ACP. Custom transports **SHOULD** document their specific connection establishment and message exchange patterns to aid interoperability. diff --git a/docs/protocol/initialization.mdx b/docs/protocol/initialization.mdx index 50307e71b..6a8a3232a 100644 --- a/docs/protocol/initialization.mdx +++ b/docs/protocol/initialization.mdx @@ -155,6 +155,10 @@ The Agent **SHOULD** specify whether it supports the following capabilities: included in `session/prompt` requests.
+ + Authentication-related capabilities supported by the Agent. + + #### Prompt capabilities As a baseline, all Agents **MUST** support `ContentBlock::Text` and `ContentBlock::ResourceLink` in `session/prompt` requests. @@ -186,6 +190,16 @@ Note: This transport has been deprecated by the MCP spec. +#### Authentication Capabilities + + + The [`logout`](./authentication#logging-out) method is available. + + + + Learn more about Authentication + + #### Session Capabilities As a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`. diff --git a/docs/protocol/overview.mdx b/docs/protocol/overview.mdx index a8dbf1dd5..71b4bc01b 100644 --- a/docs/protocol/overview.mdx +++ b/docs/protocol/overview.mdx @@ -84,6 +84,11 @@ Agents are programs that use generative AI to autonomously modify code. They typ `loadSession` capability). +Schema]}> + [End the current authenticated state](./authentication#logging-out) (requires + `agentCapabilities.auth.logout` capability). + + Schema]} @@ -196,6 +201,10 @@ All methods follow standard JSON-RPC 2.0 [error handling](https://www.jsonrpc.or - Errors include an `error` object with `code` and `message` - Notifications never receive responses (success or error) +## Conventions + +Unless explicitly defined otherwise in the schema, ACP-defined JSON object property keys use `camelCase`. String values carried by discriminator fields use `snake_case`. The JSON-RPC envelope fields (`jsonrpc`, `id`, `method`, `params`, `result`, and `error`) follow the JSON-RPC 2.0 specification. + ## Extensibility The protocol provides built-in mechanisms for adding custom functionality while maintaining compatibility: diff --git a/docs/protocol/schema.mdx b/docs/protocol/schema.mdx index 56ea67374..3e86ed115 100644 --- a/docs/protocol/schema.mdx +++ b/docs/protocol/schema.mdx @@ -3,6 +3,11 @@ title: "Schema" description: "Schema definitions for the Agent Client Protocol" --- + + The schema file can be downloaded directly from the [latest GitHub + release](https://github.com/agentclientprotocol/agent-client-protocol/releases/latest/download/schema.json). + + ## Agent Defines the interface that all ACP-compliant agents must implement. @@ -135,7 +140,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte AgentCapabilities} > Capabilities supported by the agent. - - Default: `{"loadSession":false,"mcpCapabilities":{"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false},"sessionCapabilities":{}}` + - Default: `{"auth":{},"loadSession":false,"mcpCapabilities":{"http":false,"sse":false},"promptCapabilities":{"audio":false,"embeddedContext":false,"image":false,"promptVariables":false},"sessionCapabilities":{}}` Implementation | null} > @@ -158,6 +163,49 @@ The client should disconnect, if it doesn't support this version. +### logout + +Logs out of the current authenticated state. + +After a successful logout, all new sessions will require authentication. +There is no guarantee about the behavior of already running sessions. + +#### LogoutRequest + +Request parameters for the logout method. + +Terminates the current authenticated session. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + +#### LogoutResponse + +Response to the `logout` method. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ### session/cancel @@ -1252,6 +1300,29 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte The signal that terminated the process (may be null if exited normally). +## AgentAuthCapabilities + +Authentication-related capabilities supported by the agent. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +LogoutCapabilities | null} > + Whether the agent supports the logout method. + +By supplying `\{\}` it means that the agent supports the logout method. + + + ## AgentCapabilities Capabilities supported by the agent. @@ -1272,6 +1343,12 @@ these keys. See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + +AgentAuthCapabilities} > + Authentication-related capabilities supported by the agent. + + - Default: `{}` + Whether the agent supports `session/load`. @@ -1288,7 +1365,7 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte PromptCapabilities} > Prompt capabilities supported by the agent. - - Default: `{"audio":false,"embeddedContext":false,"image":false}` + - Default: `{"audio":false,"embeddedContext":false,"image":false,"promptVariables":false}` SessionCapabilities} > @@ -1739,6 +1816,40 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/exte + +A template that supports variable substitution using \{\{variable_name\}\} syntax. + +Allows dynamic content generation by substituting variables into template strings. +Variables are resolved at processing time and can include values from context, +user input, or system state. + +Requires the `promptVariables` prompt capability when included in prompts. + + + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +Annotations | null} > + + + The template string with \{\{variable_name\}\} placeholders. + + + The discriminator value. Must be `"prompt_template"`. + +PromptVariable[]} required> + Variables available for substitution in this template. + + + + + ## ContentChunk A streamed item of content @@ -2115,6 +2226,25 @@ If not provided, the name should be used for display. for debugging or metrics purposes. (e.g. "1.0.0"). +## LogoutCapabilities + +Logout capabilities supported by the agent. + +By supplying `\{\}` it means that the agent supports the logout method. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + ## McpCapabilities MCP capabilities supported by the agent @@ -2537,6 +2667,133 @@ in prompt requests for pieces of context that are referenced in the message. - Default: `false` + + Agent supports prompt variables and templates in `session/prompt` requests. + +When enabled, the Client is allowed to include `ContentBlock::PromptTemplate` +in prompt requests with variable substitution support. + + - Default: `false` + + + +## PromptTemplateContent + +A template content block that supports variable substitution. + +Templates use \{\{variable_name\}\} syntax for variable placeholders that can be +substituted with actual values at processing time. This enables dynamic content +generation and reusable prompt templates. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + +Annotations | null} > + + + The template string with \{\{variable_name\}\} placeholders. + +PromptVariable[]} required> + Variables available for substitution in this template. + + +## PromptVariable + +A variable that can be substituted in a prompt template. + +Variables define named placeholders that can be replaced with actual values +during template processing. They can include metadata about expected types, +descriptions for user interfaces, and validation constraints. + +**Type:** Object + +**Properties:** + + + The _meta property is reserved by ACP to allow clients and agents to attach additional +metadata to their interactions. Implementations MUST NOT make assumptions about values at +these keys. + +See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + + + + Default value to use if no value is provided. + + + Human-readable description of this variable. + + + The variable name (used in \{\{variable_name\}\} placeholders). + + + Whether this variable is required for template processing. + + - Default: `false` + + +PromptVariableType | null} > + The expected type of this variable's value. + + + The current value of the variable (if set). + + +## PromptVariableType + +The expected type of a prompt variable's value. + +This helps clients provide appropriate input interfaces and validation +for prompt variables. + +**Type:** Union + + + A string value (default if not specified). + + + + A numeric value (integer or float). + + + + A boolean value (true/false). + + + + A date/time value in ISO 8601 format. + + + + A URL or URI reference. + + + + An email address. + + + + A multiline text value. + + + +A value selected from a predefined list (enum-like). + + + + + + + ## ProtocolVersion diff --git a/docs/rfds/additional-directories.mdx b/docs/rfds/additional-directories.mdx index fb2f512c3..0f65bfaf7 100644 --- a/docs/rfds/additional-directories.mdx +++ b/docs/rfds/additional-directories.mdx @@ -44,7 +44,7 @@ Without a standardized field, clients and agents must rely on implementation-spe > What are you proposing to improve the situation? -Add `additionalDirectories?: string[]` to the session lifecycle request schemas listed above and to `session/list`, and define protocol-level validation and semantics for it. +Add `additionalDirectories?: string[]` to the session lifecycle request schemas listed above, and add optional additional-root discovery metadata to `session/list` responses. The proposal is scoped to session lifecycle requests, session discovery requests, and session discovery metadata only: @@ -54,7 +54,7 @@ The proposal is scoped to session lifecycle requests, session discovery requests Agents advertise support with `sessionCapabilities.additionalDirectories`. Clients MUST gate usage on that capability. -This proposal also extends `SessionInfo` returned by `session/list` with authoritative `additionalDirectories` state, and allows `session/list` to filter on `cwd` plus `additionalDirectories`, so clients that support session discovery can recover and query the active root set for listed sessions. `session/load` and `session/resume` nevertheless remain explicit-list only: omitting `additionalDirectories` or supplying an empty array means no additional roots are activated for the resulting session, while a non-empty array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. +This proposal also allows Agents to include `additionalDirectories` in `SessionInfo` returned by `session/list`. Because Agents are not required to persist additional-root metadata, Clients treat `SessionInfo.additionalDirectories` as optional discovery metadata rather than required session state. `session/load` and `session/resume` remain explicit-list only: omitting `additionalDirectories` or supplying an empty array means no additional roots are activated for the resulting session, while a non-empty array-valued `additionalDirectories` becomes the complete resulting additional-root list for that request. Clients MAY change the additional-root list on `session/load` or `session/resume` from any previously used or reported list, as long as the request `cwd` matches the session's `cwd` and the Agent accepts the requested roots. ## Shiny future @@ -97,12 +97,6 @@ The following optional property is added to each request type named above: additionalDirectories?: string[] ``` -The following optional property is also added to `ListSessionsRequest`: - -```ts -additionalDirectories?: string[] -``` - The following optional property is also added to `SessionInfo`: ```ts @@ -117,11 +111,11 @@ additionalDirectories?: {} Clients MUST send `additionalDirectories` only when `sessionCapabilities.additionalDirectories` is present. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, any `SessionInfo.additionalDirectories` value it returns is the authoritative ordered additional-root list for that session. Agents MAY omit the field when there are no additional roots, and clients MUST treat an omitted field the same as `[]`. +If an Agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, it MAY include `SessionInfo.additionalDirectories` to report the complete ordered additional-root list associated with a listed session. Omitted and empty values are equivalent: the `SessionInfo` response reports no additional roots. Clients MUST NOT merge this field with prior values or infer additional roots from agent-specific state. -If an agent advertises `sessionCapabilities.additionalDirectories` and also supports `session/list`, `ListSessionsRequest.additionalDirectories` filters sessions by exact match on the authoritative ordered additional-root list when the field is present and non-empty. When both `cwd` and a non-empty `additionalDirectories` are present on `session/list`, both filters apply. Omitting the field or supplying an empty array means no additional-root filter is applied. +`ListSessionsRequest` is not extended with `additionalDirectories`. `session/list` filtering remains defined around existing list parameters such as `cwd`; Clients that need to find sessions by additional-root state can filter locally when Agents return `SessionInfo.additionalDirectories`. -If adopted, the session-setup, session-list, and filesystem documentation will need corresponding updates so they describe the effective root set rather than `cwd` alone as the session filesystem context or boundary. +The session-setup, session-list, and filesystem documentation describe the effective root set rather than `cwd` alone as the session filesystem context or boundary. ### Capability advertisement example @@ -142,7 +136,7 @@ If adopted, the session-setup, session-list, and filesystem documentation will n ### `session/list` example -When an agent supports both `sessionCapabilities.additionalDirectories` and `session/list`, clients may filter by `cwd`, `additionalDirectories`, or both. Each returned `SessionInfo` includes the authoritative additional-root list for that session: +When an Agent supports both `sessionCapabilities.additionalDirectories` and `session/list`, Clients may still filter by `cwd`. Agents that track additional-root state may include the complete additional-root list on each returned `SessionInfo`: ```json { @@ -150,11 +144,7 @@ When an agent supports both `sessionCapabilities.additionalDirectories` and `ses "id": 5, "method": "session/list", "params": { - "cwd": "/home/user/project", - "additionalDirectories": [ - "/home/user/shared-lib", - "/home/user/product-docs" - ] + "cwd": "/home/user/project" } } ``` @@ -192,7 +182,7 @@ ACP does not define a wire-level lexical normalization algorithm for `cwd` or `a Clients SHOULD remove exact duplicate path strings before sending the request. Clients SHOULD also avoid entries whose path string exactly matches `cwd`. Overlapping or nested roots are not semantically redundant for ACP purposes: because discovery across the effective ordered root list is ordered and implementation-defined, such entries MAY affect behavior even when they do not change the union of accessible paths. Agents MAY remove exact duplicate path strings, including entries identical to `cwd`, provided doing so preserves the first occurrence order of the remaining entries and does not expand scope. -For `session/list` filtering, matching is against the session's authoritative ordered additional-root list as surfaced in `SessionInfo.additionalDirectories`. Implementations that normalize or canonicalize path strings for comparison SHOULD apply the same platform-appropriate rule consistently to stored session state, `SessionInfo.additionalDirectories`, and `ListSessionsRequest.additionalDirectories`. +When returning `SessionInfo.additionalDirectories`, implementations that normalize or canonicalize path strings SHOULD apply the same platform-appropriate rule consistently to stored session state and the returned `SessionInfo.additionalDirectories`. ### Semantics @@ -228,10 +218,10 @@ For `NewSessionRequest`, the resulting additional root list is: For `LoadSessionRequest` and `ResumeSessionRequest`: -- when `additionalDirectories` is present with a non-empty array value, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored additional roots; +- when `additionalDirectories` is present with a non-empty array value, it is the complete resulting list of additional roots for the active session, even if that list differs from the session's previously stored or reported additional roots, provided the request `cwd` matches the session's `cwd`; - when omitted or present as an empty array, the resulting additional root list is `[]`. -Agents MUST NOT implicitly reactivate stored additional roots that were not supplied on the `session/load` or `session/resume` request. Supplying `additionalDirectories` on `session/load` or `session/resume` is always allowed when the capability is advertised, and doing so may preserve, replace, reduce, or expand the session's previously stored additional-root list for the resulting active session, subject to validation and policy checks. Clients that need to preserve a session's additional roots across restarts or across client instances MUST obtain, persist, or reconstruct the full list and resend it on load or resume. When `session/list` is available, `SessionInfo.additionalDirectories` provides the authoritative current additional-root list for that purpose. +Agents MUST NOT implicitly reactivate stored additional roots that were not supplied on the `session/load` or `session/resume` request. Supplying `additionalDirectories` on `session/load` or `session/resume` is allowed when the capability is advertised and `cwd` matches the session being loaded or resumed, and doing so may preserve, replace, reduce, or expand the session's previously stored or reported additional-root list for the resulting active session, subject to validation and policy checks. Clients that need to preserve a session's additional roots across restarts or across client instances MUST obtain, persist, or reconstruct the full list and resend it on load or resume. When `session/list` includes `SessionInfo.additionalDirectories`, that value can help with this purpose, but Clients MUST NOT assume it is always returned. For `ForkSessionRequest`: @@ -291,7 +281,7 @@ A client that sends `additionalDirectories`: - SHOULD remove exact duplicate path strings and entries identical to `cwd` before sending; and - MUST NOT assume an agent will infer extra roots from project metadata, directory conventions, or prior session state. -If a client mediates filesystem access through ACP client capabilities such as `fs/read_text_file` and `fs/write_text_file`, it MUST enforce the effective root set for that session when authorizing path-based access. ACP's filesystem methods are client-mediated and operate on absolute paths, so the client remains responsible for boundary enforcement in those flows. When the client learns about an existing session through `session/list`, it SHOULD use `SessionInfo.additionalDirectories` together with `cwd` as the authoritative current root set for those checks until a subsequent lifecycle request establishes a different one. +If a client mediates filesystem access through ACP client capabilities such as `fs/read_text_file` and `fs/write_text_file`, it MUST enforce the effective root set for that session when authorizing path-based access. ACP's filesystem methods are client-mediated and operate on absolute paths, so the client remains responsible for boundary enforcement in those flows. When the client learns about an existing session through `session/list`, it SHOULD use `cwd` together with any `SessionInfo.additionalDirectories` entries returned for that session as the reported root set. Omitted and empty values report no additional roots. Any subsequent lifecycle request establishes the resulting active root set explicitly. If a client launches an agent with direct filesystem access, `additionalDirectories` is not, by itself, a sandbox. Clients that need root boundaries to be enforced in that deployment model SHOULD apply operating-system or runtime sandboxing consistent with the declared root set. @@ -392,9 +382,9 @@ Updated agents MUST continue to accept requests that do not include the field. Older implementations may validate request objects strictly against older schemas and MAY reject unknown fields. Clients therefore MUST gate usage on `sessionCapabilities.additionalDirectories`. -This proposal intentionally does not extend the responses to `session/new`, `session/load`, `session/resume`, or `session/fork` to surface authoritative additional-root state directly. That remains consistent with existing ACP response shapes, which also do not return `cwd`. Instead, when `session/list` is supported, `SessionInfo.additionalDirectories` exposes the authoritative ordered additional-root list for listed sessions. `SessionInfoUpdate` remains unchanged because this RFD does not define mid-session mutation of `additionalDirectories`. Clients that need multi-root continuity across `session/load` or `session/resume` MUST still send the full intended list explicitly. +This proposal intentionally does not extend the responses to `session/new`, `session/load`, `session/resume`, or `session/fork` to surface additional-root state directly. That remains consistent with existing ACP response shapes, which also do not return `cwd`. Instead, when `session/list` is supported, Agents MAY expose the complete ordered additional-root list for listed sessions through `SessionInfo.additionalDirectories`. Omitted and empty values report no additional roots for that `SessionInfo`. `SessionInfoUpdate` remains unchanged because this RFD does not define mid-session mutation of `additionalDirectories`. Clients that need multi-root continuity across `session/load` or `session/resume` MUST still send the full intended list explicitly, and MAY change that list from a previously used or reported list as long as the request `cwd` matches the session's `cwd`. -`session/list` filtering no longer remains `cwd`-only: sessions may be filtered by `cwd`, by `additionalDirectories`, or by both together. Sessions that differ by `additionalDirectories` are therefore both distinguishable and filterable through `SessionInfo.additionalDirectories` and `ListSessionsRequest.additionalDirectories`. +`session/list` filtering remains independent of `additionalDirectories`. Sessions that differ by `additionalDirectories` are distinguishable only when the Agent surfaces that state through `SessionInfo.additionalDirectories`; Clients that need additional-root matching can filter those returned sessions locally. This RFD does not add a new RPC method. It also does not change the meaning of `cwd`, `sessionId`, or `mcpServers`. @@ -429,7 +419,7 @@ Clients MUST gate `additionalDirectories` on `sessionCapabilities.additionalDire ### Why not restore stored roots on `session/load` or `session/resume` when the field is omitted? -Even with `SessionInfo.additionalDirectories` available through `session/list`, implicit restoration would still let an agent reactivate filesystem scope that the current request did not state explicitly. That is undesirable for clients that do not use `session/list`, for clients resuming a session by ID without first listing it, and for clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field or supplying an empty array activates none, while supplying a non-empty array is explicitly allowed and sets the complete resulting additional-root list for that request. +Even when `SessionInfo.additionalDirectories` is available through `session/list`, implicit restoration would still let an Agent reactivate filesystem scope that the current request did not state explicitly. Some Agents also do not persist or surface this state at all. That is undesirable for Clients that do not use `session/list`, for Clients resuming a session by ID without first listing it, and for Clients that want request-time control over the active root set. This proposal therefore keeps load and resume explicit-list only for additional roots: omitting the field or supplying an empty array activates none, while supplying a non-empty array is explicitly allowed and sets the complete resulting additional-root list for that request. That list may differ from any previously used or reported list, as long as the request `cwd` matches the session's `cwd` and the Agent accepts the requested roots. ### What alternative approaches did you consider, and why did you settle on this one? @@ -443,4 +433,5 @@ This proposal is preferred because it is additive, keeps `cwd` semantics stable, ## Revision history +- 2026-05-21: Moved to Preview. - 2026-03-24: Initial draft. diff --git a/docs/rfds/custom-llm-endpoint.mdx b/docs/rfds/custom-llm-endpoint.mdx index 275e569df..222824c75 100644 --- a/docs/rfds/custom-llm-endpoint.mdx +++ b/docs/rfds/custom-llm-endpoint.mdx @@ -174,7 +174,7 @@ interface ProvidersListResponse { `providers/set` updates the full configuration for one provider id. ```typescript -interface ProvidersSetRequest { +interface SetProviderRequest { /** Provider id to configure. */ id: string; @@ -195,7 +195,7 @@ interface ProvidersSetRequest { _meta?: Record; } -interface ProvidersSetResponse { +interface SetProviderResponse { /** Extension metadata */ _meta?: Record; } @@ -204,7 +204,7 @@ interface ProvidersSetResponse { ### `providers/disable` ```typescript -interface ProvidersDisableRequest { +interface DisableProviderRequest { /** Provider id to disable. */ id: string; @@ -212,7 +212,7 @@ interface ProvidersDisableRequest { _meta?: Record; } -interface ProvidersDisableResponse { +interface DisableProviderResponse { /** Extension metadata */ _meta?: Record; } diff --git a/docs/rfds/diff-delete.mdx b/docs/rfds/diff-delete.mdx index bccdc05fc..204618619 100644 --- a/docs/rfds/diff-delete.mdx +++ b/docs/rfds/diff-delete.mdx @@ -2,7 +2,7 @@ title: "Represent deleted files in diff" --- -Author(s): [anna239](https://github.com/benbrandt) +Author(s): [anna239](https://github.com/anna239) ## Elevator pitch diff --git a/docs/rfds/logout-method.mdx b/docs/rfds/logout-method.mdx index 932205dad..bb62738f3 100644 --- a/docs/rfds/logout-method.mdx +++ b/docs/rfds/logout-method.mdx @@ -66,7 +66,7 @@ interface LogoutResponse { ### Capability Advertisement -The `logout` capability should be advertised within a new `auth` object in `AgentCapabilities`: +The `logout` capability is advertised within the `auth` object in `AgentCapabilities`: ```typescript interface AgentCapabilities { @@ -177,7 +177,7 @@ interface LogoutCapabilities { ### Behavior 1. **Pre-condition**: The client should only call `logout` if: - - The agent advertises `auth.logout: {}` + - The agent advertises `agentCapabilities.auth.logout: {}` 2. **Agent responsibilities**: - Invalidate any stored tokens or credentials as appropriate @@ -207,4 +207,6 @@ The RFD intentionally does not mandate a specific behavior to allow flexibility. ## Revision history +- 2026-05-21: RFD marked as Completed; `logout` is stabilized +- 2026-05-17: Moved to Preview. - 2026-02-02: Initial draft diff --git a/docs/rfds/mcp-over-acp.mdx b/docs/rfds/mcp-over-acp.mdx index 353d02477..12a3c99bc 100644 --- a/docs/rfds/mcp-over-acp.mdx +++ b/docs/rfds/mcp-over-acp.mdx @@ -34,24 +34,27 @@ This enables patterns like: ### How it works -When the client connects, the agent advertises MCP-over-ACP support via `mcpCapabilities.acp` in its `InitializeResponse`. If supported, the client can add MCP servers to a `session/new` request with `"transport": "acp"` and an `id` that identifies the server: +When the client connects, the agent advertises MCP-over-ACP support via `mcpCapabilities.acp` in its `InitializeResponse`. If supported, the client can add MCP servers to a `session/new` request with `"type": "acp"` and an `id` that identifies the server: ```json { "tools": { - "mcpServers": { - "project-tools": { - "transport": "acp", + "mcpServers": [ + { + "type": "acp", + "name": "project-tools", "id": "550e8400-e29b-41d4-a716-446655440000" } - } + ] } } ``` The `id` is generated by the component providing the MCP server. -When the agent connects to the MCP server, an `mcp/connect` message is sent with the MCP server's `id`. This returns a fresh `connectionId`. MCP messages are then sent back and forth using `mcp/message` requests. Finally, `mcp/disconnect` signals that the connection is closing. +When the agent connects to the MCP server, an `mcp/connect` message is sent with the MCP server's `id`. This returns a fresh `connectionId`. MCP messages are then sent back and forth using `mcp/message` requests and notifications. Finally, `mcp/disconnect` signals that the connection is closing. + +`mcp/connect` and `mcp/disconnect` are initiated by the side connecting to the ACP-transport MCP server. In the direct client-provided server case, that means the agent sends them to the client. Once connected, `mcp/message` is bidirectional: the agent can send MCP client-originated requests to the server, and the server can send MCP server-originated requests or notifications back to the agent. ### Bridging and compatibility @@ -78,6 +81,9 @@ sequenceDiagram Agent->>Client: mcp/message (list_files tool call) Client-->>Agent: file listing results + Client->>Agent: mcp/message (server callback or notification) + Agent-->>Client: callback result, if request + Agent-->>Client: response using tool results Agent->>Client: mcp/disconnect (connectionId: "conn-1") @@ -119,7 +125,7 @@ Agents advertise MCP-over-ACP support via the [`mcpCapabilities`](/protocol/sche } ``` -When `mcpCapabilities.acp` is `true`, the agent can handle MCP servers declared with `"transport": "acp"` natively - it will send `mcp/connect`, `mcp/message`, and `mcp/disconnect` messages through the ACP channel. +When `mcpCapabilities.acp` is `true`, the agent can handle MCP servers declared with `"type": "acp"` natively. It will initiate `mcp/connect` and `mcp/disconnect` through the ACP channel, and both sides can exchange MCP payloads with `mcp/message`. Clients don't need to advertise anything - they simply check the agent's capabilities to determine whether bridging is needed. @@ -127,30 +133,27 @@ Clients don't need to advertise anything - they simply check the agent's capabil ### MCP transport schema extension -We extend the MCP JSON schema to include ACP as a transport option: +We extend the MCP server JSON schema to include ACP as a transport option: ```json { "type": "object", "properties": { - "transport": { + "type": { "type": "string", - "enum": ["stdio", "http", "acp"] + "const": "acp" + }, + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "_meta": { + "type": ["object", "null"] } }, - "allOf": [ - { - "if": { "properties": { "transport": { "const": "acp" } } }, - "then": { - "properties": { - "id": { - "type": "string" - } - }, - "required": ["id"] - } - } - ] + "required": ["type", "name", "id"] } ``` @@ -164,13 +167,13 @@ We extend the MCP JSON schema to include ACP as a transport option: "method": "mcp/connect", "params": { "acpId": "550e8400-e29b-41d4-a716-446655440000", - "meta": { ... } + "_meta": { ... } } } -// Response: +// Response result: { "connectionId": "conn-123", - "meta": { ... } + "_meta": { ... } } // Close MCP connection @@ -178,27 +181,49 @@ We extend the MCP JSON schema to include ACP as a transport option: "method": "mcp/disconnect", "params": { "connectionId": "conn-123", - "meta": { ... } + "_meta": { ... } } } +// Response result: +{ + "_meta": { ... } +} ``` **MCP message exchange:** +`mcp/message` is bidirectional. Either side can send the following request or notification shape on an established `connectionId`. + ```json -// Send MCP message (bidirectional - works agent→client or client→agent) +// Send MCP request +{ + "id": 123, + "method": "mcp/message", + "params": { + "connectionId": "conn-123", + "method": "", + "params": { ... }, + "_meta": { ... } + } +} +// Response result: +{ + ... inner MCP result payload ... +} + +// Send MCP notification { "method": "mcp/message", "params": { "connectionId": "conn-123", "method": "", "params": { ... }, - "meta": { ... } + "_meta": { ... } } } ``` -The inner MCP message fields (`method`, `params`) are flattened into the params object. Whether the wrapped message is a request or notification is determined by the presence of an `id` field in the outer JSON-RPC envelope, following JSON-RPC conventions. +The inner MCP message fields (`method`, `params`) are flattened into the params object. The `params` field is optional; if omitted or set to `null`, the inner MCP message has no params. Whether the wrapped message is a request or notification is determined by the presence of an `id` field in the outer JSON-RPC envelope, following JSON-RPC conventions. For requests, the ACP response result is the inner MCP result payload, and inner MCP errors are represented with the outer JSON-RPC error response. ### Routing by ID @@ -222,7 +247,7 @@ Not all agents will support MCP-over-ACP natively. To maintain compatibility, it **How bridging works:** -When a client provides an MCP server with `"transport": "acp"`, and the agent doesn't advertise `mcpCapabilities.acp: true`, a bridge can: +When a client provides an MCP server with `"type": "acp"`, and the agent doesn't advertise `mcpCapabilities.acp: true`, a bridge can: 1. Rewrite the MCP server declaration in `session/new` to use stdio or HTTP transport 2. Spawn the appropriate shim process or HTTP server diff --git a/docs/rfds/model-config-category.mdx b/docs/rfds/model-config-category.mdx new file mode 100644 index 000000000..376b6c986 --- /dev/null +++ b/docs/rfds/model-config-category.mdx @@ -0,0 +1,83 @@ +--- +title: "Model Config Option Category" +--- + +- Author(s): [anna239](https://github.com/anna239) + +## Elevator pitch + +Add a new `model_config` category to session configuration options, so that agents can expose model-related parameters (context size, speed/quality trade-offs, etc) and clients can group them alongside the main model selector in the UI. + +## Status quo + +The `category` field on `SessionConfigOption` currently supports three values: `mode`, `model`, and `thought_level`. This works well when the model is a single selector, but some agents expose many model configurations — context window size, speed tier, and similar settings that logically belong next to the model picker. + +## What we propose to do about it + +Add a `model_config` variant to `SessionConfigOptionCategory`. + +Agents tag any model-related parameters with `"category": "model_config"`, and clients render them near the primary `model` selector — for example as secondary controls within a model-picker popover or panel. + +### Relationship to `thought_level` + +Once `model_config` exists, `thought_level` is semantically a special case of a model configuration parameter. We keep `thought_level` as-is for backward compatibility — existing clients already handle it — but new model-related options should use `model_config`. + +## Shiny future + +Agents expose rich, parameterized model configurations over ACP. + +## Implementation details and plan + +### JSON format + +An agent declares model-config options in `configOptions`: + +```json +{ + "configOptions": [ + { + "id": "model", + "name": "Model", + "category": "model", + "type": "select", + "currentValue": "sonnet-4.5", + "options": [ + { "value": "sonnet-4.5", "name": "Sonnet 4.5" }, + { "value": "opus-4.6", "name": "Opus 4.6" } + ] + }, + { + "id": "context_size", + "name": "Context Size", + "category": "model_config", + "type": "select", + "currentValue": "200k", + "options": [ + { "value": "200k", "name": "200K" }, + { "value": "1m", "name": "1M" } + ] + }, + { + "id": "fast_mode", + "name": "Fast Mode", + "category": "model_config", + "type": "boolean", + "currentValue": false + } + ] +} +``` + +### Client behavior + +- Clients SHOULD render `model_config` options near the `model` selector (e.g., in the same popover or panel). +- Clients that do not recognize the category MUST handle it gracefully per the existing spec — the option still renders, just without special placement. +- No new client capability negotiation is needed. + +### Should `thought_level` move under `model_config`? + +Not now. Existing clients already handle `thought_level`, so changing its semantics would be a breaking change. New model-related parameters should use `model_config`; `thought_level` remains for backward compatibility. + +## Revision history + +- 2026-04-08: Initial proposal diff --git a/docs/rfds/rust-sdk-v1.mdx b/docs/rfds/rust-sdk-v1.mdx index b29505826..d7a5930ee 100644 --- a/docs/rfds/rust-sdk-v1.mdx +++ b/docs/rfds/rust-sdk-v1.mdx @@ -865,7 +865,7 @@ The new SDK is organized into several crates with clear responsibilities: ### Current status -A working implementation exists in the [symposium-dev/symposium-acp](https://github.com/symposium-dev/symposium-acp) repository and is published on crates.io. It powers: +The implementation has been upstreamed to [agentclientprotocol/rust-sdk](https://github.com/agentclientprotocol/rust-sdk) for preview. The original [`sacp`](https://github.com/symposium-dev/symposium-acp) crates remain published on crates.io and power: - The conductor (proxy chain orchestration) - patchwork-rs (programmatic agent orchestration) @@ -873,12 +873,13 @@ A working implementation exists in the [symposium-dev/symposium-acp](https://git ### Migration path -The transition involves importing the `sacp` implementation into this repository: +The transition involves upstreaming the `sacp` implementation to the `agentclientprotocol/rust-sdk` repository and stabilizing it after preview: -1. **Import `sacp` crates** into this repository with the new `agent-client-protocol-*` naming -2. **Release `agent-client-protocol` v1.0** with the new builder-based API -3. **Deprecate `sacp` crates** on crates.io, pointing users to the `agent-client-protocol` family -4. **Provide migration guidance** for users of the current v0.x SDK +1. **Import `sacp` crates** to `agentclientprotocol/rust-sdk` with the new `agent-client-protocol-*` naming +2. **Preview the upstreamed SDK** to collect feedback on the new builder-based API +3. **Release `agent-client-protocol` v1.0** when this RFD is marked Completed +4. **Deprecate `sacp` crates** on crates.io, pointing users to the `agent-client-protocol` family +5. **Provide migration guidance** for users of the current v0.x SDK Most users will find the migration straightforward - the builder pattern is more ergonomic than the trait-based approach, so the new code is often simpler than the old. @@ -910,10 +911,11 @@ This is a potential future enhancement - enum derives could dispatch to differen ### What changes are needed before stabilizing? -We are in the process of changing how response messages work to simplify the implementation of the conductor. Before stabilizing we should do a thorough review of the methods and look for candidates that can be removed or simplified. +Now that the implementation has been upstreamed, preview feedback should focus on API polish, method review, and identifying any candidates that can be removed or simplified before the 1.0 release. The conductor is feature complete but the support for MCP-over-ACP needs a few minor improvements (in particular, it should detect when the agent only supports stdio bridging and not attempt to use HTTP, which it currently does not). ## Revision history +- 2026-05-12: Moved to Preview after the initial crate import was upstreamed to agentclientprotocol/rust-sdk. - Initial draft based on working implementation in symposium-acp repository. diff --git a/docs/rfds/streamable-http-websocket-transport.mdx b/docs/rfds/streamable-http-websocket-transport.mdx index 8a79c221a..5ceb0fcfc 100644 --- a/docs/rfds/streamable-http-websocket-transport.mdx +++ b/docs/rfds/streamable-http-websocket-transport.mdx @@ -9,9 +9,9 @@ title: "Streamable HTTP & WebSocket Transport" > What are you proposing to change? -ACP needs a standard remote transport. We propose a **single long-lived GET stream** for all server→client messages, with **POST** for client→server messages, and **WebSocket upgrade** as an alternative on the same endpoint. A single `/acp` endpoint supports two connectivity profiles: +ACP needs a standard remote transport. We propose **long-lived GET streams** for server→client messages (one connection-scoped plus one per session), with **POST** for client→server messages, and **WebSocket upgrade** as an alternative on the same endpoint. A single `/acp` endpoint supports two connectivity profiles: -- **Streamable HTTP (POST/GET/DELETE)** — Single long-lived SSE stream per connection for all server→client messages (responses and notifications). POST requests return immediately (202 Accepted, except `initialize`). Requires HTTP/2. +- **Streamable HTTP (POST/GET/DELETE)** — Long-lived SSE streams per connection: one connection-scoped stream for connection-level server→client messages, plus one session-scoped stream per session for session-level messages. POST requests return immediately (202 Accepted, except `initialize`). Requires HTTP/2. - **WebSocket upgrade (GET with `Upgrade: websocket`)** — persistent, full-duplex, low-latency bidirectional messaging. Clients that support remote ACP over HTTP MUST support both Streamable HTTP and WebSocket. This allows servers to support only WebSocket if they choose, simplifying deployment. @@ -32,11 +32,11 @@ ACP only has stdio. There is no standard remote transport, which causes fragment ACP adopts a streamable HTTP transport with three key characteristics: -1. **Single long-lived GET stream per connection** — All server→client messages (responses to requests and unsolicited notifications) are delivered via a single SSE stream opened with GET. This includes responses to client requests (correlated by JSON-RPC `id`), server-initiated notifications (no `id`), and server-to-client requests like `request_permission` (with `id`, client responds via POST). The GET stream is scoped to `Acp-Connection-Id` and delivers messages for all sessions within that connection. Session identity is carried in the JSON-RPC message body (`sessionId` field). +1. **Long-lived GET streams (one connection-scoped, one per session)** — All server→client messages (responses to requests and unsolicited notifications) are delivered via SSE streams opened with GET. The **connection-scoped stream** (scoped to `Acp-Connection-Id`) carries connection-level messages: responses to `session/new` and `session/load` (which the client cannot receive on a session-scoped stream because it does not yet have a `sessionId`), and any server-initiated messages not tied to a specific session. The **session-scoped stream** (scoped to `Acp-Connection-Id` + `Acp-Session-Id`) carries all messages for a single session: session update notifications, server-to-client requests like `request_permission`, and responses to session-scoped POSTs like `session/prompt` and `session/cancel`. Responses are correlated to the POST that originated them by JSON-RPC `id`. -2. **POST requests return immediately (except initialize)** — Client→server messages are sent via POST. Most POST requests return `202 Accepted` immediately with an empty body. The actual response comes later on the GET stream, correlated by JSON-RPC `id`. The `initialize` request is special: it returns `200 OK` with a JSON response body containing capabilities and the `Acp-Connection-Id`. The `Acp-Connection-Id` is also included in the response header. +2. **POST requests return immediately (except initialize)** — Client→server messages are sent via POST. Most POST requests return `202 Accepted` immediately with an empty body. The actual response comes later on the appropriate GET stream, correlated by JSON-RPC `id`. The `initialize` request is special: it returns `200 OK` with a JSON response body containing capabilities and the `Acp-Connection-Id`. The `Acp-Connection-Id` is also included in the response header. -3. **Requires HTTP/2** — Streamable HTTP transport MUST use HTTP/2. This provides multiplexing for concurrent POST requests while maintaining a single long-lived GET stream, and improves efficiency for high-frequency message exchanges. +3. **Requires HTTP/2** — Streamable HTTP transport MUST use HTTP/2. This provides multiplexing for concurrent POST requests while maintaining long-lived GET streams (one connection-scoped plus one per session), and improves efficiency for high-frequency message exchanges. ### 4. Adds WebSocket as a first-class upgrade on the same endpoint @@ -50,12 +50,12 @@ Clients MUST accept, store, and return cookies set by the server on all HTTP-bas ### 6. Defines a unified routing model -| Method | Upgrade Header? | Behavior | -| -------- | -------------------- | ----------------------------------------------------------------------------------------------------------- | -| `POST` | — | Send JSON-RPC message. `initialize` returns 200 with JSON body. All others return 202 Accepted immediately. | -| `GET` | No | Open connection-scoped SSE stream for all server→client messages. Requires `Acp-Connection-Id`. | -| `GET` | `Upgrade: websocket` | Upgrade to WebSocket for full-duplex messaging | -| `DELETE` | — | Terminate the connection | +| Method | Upgrade Header? | Behavior | +| -------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `POST` | — | Send JSON-RPC message. `initialize` returns 200 with JSON body. All others return 202 Accepted immediately. | +| `GET` | No | Open SSE stream. `Acp-Connection-Id` alone → connection-scoped stream. `Acp-Connection-Id` + `Acp-Session-Id` → session-scoped stream. | +| `GET` | `Upgrade: websocket` | Upgrade to WebSocket for full-duplex messaging | +| `DELETE` | — | Terminate the connection | ### 7. Preserves the full ACP lifecycle @@ -96,9 +96,9 @@ The `initialize` → `initialized` → messages → close lifecycle is identical ACP over Streamable HTTP uses two HTTP headers for connection and session identity, plus JSON-RPC message fields: -- **`Acp-Connection-Id`** (HTTP header) — Transport-level identifier returned by the server in the `initialize` response. Required on all HTTP requests after `initialize` and on the GET stream. Binds requests to an initialized connection and its negotiated capabilities. -- **`Acp-Session-Id`** (HTTP header) — Session-level identifier returned in the `session/new` response body. Required on all session-scoped POST requests (`session/prompt`, `session/cancel`, permission responses, etc.). Enables routing and debugging. -- **`sessionId`** (JSON-RPC field) — Session-level identifier also included in JSON-RPC `params` for session-scoped methods and in responses on the GET stream. A single connection may host multiple sessions, each with its own `sessionId`. +- **`Acp-Connection-Id`** (HTTP header) — Transport-level identifier returned by the server in the `initialize` response. Required on all HTTP requests after `initialize` and on every GET stream (both connection-scoped and session-scoped). Binds requests to an initialized connection and its negotiated capabilities. +- **`Acp-Session-Id`** (HTTP header) — Session-level identifier returned in the `session/new` response body. Required on all session-scoped POST requests (`session/prompt`, `session/cancel`, permission responses, etc.) and on the session-scoped GET stream. +- **`sessionId`** (JSON-RPC field) — Session-level identifier also included in JSON-RPC `params` for session-scoped methods and in responses on the GET streams. A single connection may host multiple sessions, each with its own `sessionId` and its own session-scoped GET stream. ### Streamable HTTP Message Flow @@ -114,11 +114,11 @@ Client Server │ Acp-Connection-Id: │ Response includes Acp-Connection-Id header │ Content-Type: application/json │ │ │ - │ ═══ Open GET Stream ═══ │ + │ ═══ Open Connection-Scoped GET ═══│ │ │ - │─── GET /acp ──────────────────────>│ Open long-lived SSE stream - │ Acp-Connection-Id: │ for all server→client messages - │ Accept: text/event-stream │ + │─── GET /acp ──────────────────────>│ Open long-lived connection-scoped SSE stream + │ Acp-Connection-Id: │ for connection-level server→client messages + │ Accept: text/event-stream │ (no Acp-Session-Id header) │ ┌─────────────────────│ (SSE stream open) │ │ │ │ │ │ @@ -130,9 +130,17 @@ Client Server │<────── 202 Accepted ───────────────│ (returns immediately) │ │ │ │<─────────────│─ SSE event ─────────│ { id: 2, result: { sessionId: "sess_abc123" } } - │ │ │ (response comes on GET stream) + │ │ │ (response on connection-scoped stream) + │ │ │ + │ ═══ Open Session-Scoped GET ═══ │ + │ │ + │─── GET /acp ──────────────────────>│ Open long-lived session-scoped SSE stream + │ Acp-Connection-Id: │ for sess_abc123 + │ Acp-Session-Id: sess_abc123 │ + │ Accept: text/event-stream │ + │ ┌─────────────────────│ (SSE stream open) │ │ │ - │ ═══ Prompt Flow ═══ │ + │ ═══ Prompt Flow ═══ │ (all events below arrive on the session-scoped stream) │ │ │─── POST /acp ─────────────────────>│ { method: "session/prompt", id: 3, │ Acp-Connection-Id: │ params: { sessionId: "sess_abc123", prompt } } @@ -198,22 +206,27 @@ Client Server │<────── 200 OK ─────────────────────│ { id: 1, result: { capabilities, connectionId } } │ Acp-Connection-Id: │ │ │ - │─── GET /acp ──────────────────────>│ Open new GET stream + │─── GET /acp ──────────────────────>│ Open new connection-scoped GET stream │ Acp-Connection-Id: │ │ ┌─────────────────────│ (SSE stream open) │ │ │ + │─── GET /acp ──────────────────────>│ Open session-scoped GET stream for sess_abc123 + │ Acp-Connection-Id: │ + │ Acp-Session-Id: sess_abc123 │ + │ ┌─────────────────────│ (SSE stream open) + │ │ │ │─── POST /acp ─────────────────────>│ { method: "session/load", id: 2, │ Acp-Connection-Id: │ params: { sessionId: "sess_abc123", cwd } } │ Acp-Session-Id: sess_abc123 │ │ │ │<────── 202 Accepted ───────────────│ │ │ │ - │<─────────────│─ SSE event ─────────│ notification: UserMessageChunk (sessionId: "sess_abc123") - │<─────────────│─ SSE event ─────────│ notification: AgentMessageChunk (sessionId: "sess_abc123") - │<─────────────│─ SSE event ─────────│ notification: ToolCall (sessionId: "sess_abc123") - │<─────────────│─ SSE event ─────────│ notification: ToolCallUpdate (sessionId: "sess_abc123") + │<─────────────│─ SSE event ─────────│ notification: UserMessageChunk (on session-scoped stream) + │<─────────────│─ SSE event ─────────│ notification: AgentMessageChunk (on session-scoped stream) + │<─────────────│─ SSE event ─────────│ notification: ToolCall (on session-scoped stream) + │<─────────────│─ SSE event ─────────│ notification: ToolCallUpdate (on session-scoped stream) │<─────────────│─ SSE event ─────────│ { id: 2, result: { sessionId: "sess_abc123" } } - │ │ │ (response comes on GET stream) + │ │ │ (response on connection-scoped stream) │ │ │ │ ═══ Connection Termination ═══ │ │ │ @@ -228,6 +241,7 @@ Client Server - POST `Content-Type` **MUST** be `application/json` (415 otherwise). - GET `Accept` **MUST** include `text/event-stream` (406 otherwise). - POST requests for session-scoped operations **MUST** include both `Acp-Connection-Id` and `Acp-Session-Id` headers. +- GET requests without `Upgrade: websocket` **MUST** include `Acp-Connection-Id`. If `Acp-Session-Id` is also present, the stream is session-scoped; otherwise it is connection-scoped. An unknown `Acp-Session-Id` for the given connection returns 404. - Batch JSON-RPC requests return 501. - HTTP/2 is **REQUIRED** for Streamable HTTP transport. @@ -260,7 +274,9 @@ GET /acp └── No → SSE stream handler ├── Missing Acp-Connection-Id? → 400 Bad Request ├── Unknown Acp-Connection-Id? → 404 Not Found - └── Valid Acp-Connection-Id → Open connection-scoped SSE stream + ├── Has Acp-Session-Id unknown for this connection? → 404 Not Found + ├── Has Acp-Session-Id → Open session-scoped SSE stream + └── No Acp-Session-Id → Open connection-scoped SSE stream POST /acp ├── Initialize request (no Acp-Connection-Id)? → Create connection, return 200 with JSON @@ -281,7 +297,7 @@ Connection { connection_id: String, // Acp-Connection-Id capabilities: NegotiatedCapabilities, sessions: HashMap, // keyed by sessionId (JSON-RPC field) - get_stream: Option, // Single GET stream for this connection + get_stream: Option, // Connection-scoped GET stream to_agent_tx: mpsc::Sender, from_agent_rx: Arc>>, handle: JoinHandle<()>, @@ -289,11 +305,12 @@ Connection { Session { session_id: String, // sessionId (JSON-RPC field) + get_stream: Option, // Session-scoped GET stream // session-specific state } ``` -The agent task is spawned once per connection. A single GET SSE stream delivers all server→client messages for that connection, regardless of which session they belong to. Sessions are identified by the `sessionId` field in JSON-RPC messages. The transport layer adapts channels to the wire format (SSE events for HTTP, text frames for WebSocket). +The agent task is spawned once per connection. Server→client messages are routed to either the connection-scoped GET stream or the appropriate session-scoped GET stream based on whether the message is tied to a specific session. Sessions are identified by the `sessionId` field in JSON-RPC messages. The transport layer adapts channels to the wire format (SSE events for HTTP, text frames for WebSocket). ### Comparing to MCP Streamable HTTP @@ -302,10 +319,10 @@ The agent task is spawned once per connection. A single GET SSE stream delivers | POST for all client→server messages | ✅ | Compliant | | Accept header validation (406) | ✅ | Compliant | | Notifications/responses return 202 | ✅ (except `initialize` returns 200) | Mostly compliant | -| Requests return SSE stream | ❌ (single long-lived GET stream instead) | Documented deviation | +| Requests return SSE stream | ❌ (long-lived GET streams instead) | Documented deviation | | Session ID on initialize response | ✅ (`Acp-Connection-Id`) | Compliant (renamed) | | Session ID required on subsequent requests | ✅ (`Acp-Connection-Id` + `Acp-Session-Id`) | Compliant (extended) | -| GET opens SSE stream | ✅ (single connection-scoped stream) | Compliant | +| GET opens SSE stream | ✅ (connection-scoped + session-scoped) | Compliant (extended) | | DELETE terminates session | ✅ (terminates connection) | Compliant | | 404 for unknown sessions | ✅ (unknown connection IDs) | Compliant | | Batch requests | ❌ (returns 501) | Documented deviation | @@ -314,10 +331,10 @@ The agent task is spawned once per connection. A single GET SSE stream delivers ### Deviations from MCP Streamable HTTP -1. **Single long-lived GET stream**: MCP opens a new SSE stream for each request response. ACP uses a single long-lived GET stream per connection for all server→client messages. POST requests (except `initialize`) return 202 Accepted immediately, and responses arrive on the GET stream correlated by JSON-RPC `id`. +1. **Long-lived GET streams (connection-scoped + per-session)**: MCP opens a new SSE stream for each request response. ACP uses long-lived GET streams per connection — one connection-scoped stream plus one session-scoped stream per session. POST requests (except `initialize`) return 202 Accepted immediately, and responses arrive on the appropriate GET stream correlated by JSON-RPC `id`. 2. **Initialize returns JSON directly**: MCP's `initialize` returns an SSE stream. ACP's `initialize` returns `200 OK` with a JSON response body containing capabilities and `connectionId`. The `Acp-Connection-Id` is also included in the response header. 3. **HTTP/2 required**: ACP requires HTTP/2 for multiplexing concurrent POST requests alongside the long-lived GET stream. -4. **Two-header model**: ACP uses both `Acp-Connection-Id` (for connection identity) and `Acp-Session-Id` (for session identity on POST requests). MCP only uses `Mcp-Session-Id`. This allows ACP to distinguish connection-level state from session-level operations while supporting multiple concurrent sessions on one connection. +4. **Two-header model**: ACP uses both `Acp-Connection-Id` (for connection identity) and `Acp-Session-Id` (for session identity on POST requests and on the session-scoped GET stream). MCP only uses `Mcp-Session-Id`. This allows ACP to distinguish connection-level state from session-level operations while supporting multiple concurrent sessions on one connection. 5. **WebSocket extension**: MCP doesn't define WebSocket. ACP adds it as a required client capability. Clients MUST support WebSocket, and servers MAY choose to only support WebSocket connections. 6. **Cookie support required**: Clients MUST handle cookies on HTTP transports for the duration of the connection, enabling sticky sessions and per-connection server state. 7. **No batch requests**: Returns 501. May be added later. @@ -336,11 +353,11 @@ The agent task is spawned once per connection. A single GET SSE stream delivers ### Why not just use MCP Streamable HTTP as-is? -MCP opens a new SSE stream for each request response, which creates many long-lived connections and complicates load balancing. ACP uses a single long-lived GET stream per connection for all server→client messages, dramatically reducing connection count and simplifying sticky session routing. This is better suited for ACP's bidirectional, multi-session nature. +MCP opens a new SSE stream for each request response, which creates many short-lived connections and complicates load balancing. ACP uses long-lived GET streams per connection (one connection-scoped plus one per session), dramatically reducing connection count and simplifying sticky session routing. This is better suited for ACP's bidirectional, multi-session nature. ### How are sessions identified? -ACP uses `Acp-Connection-Id` in HTTP headers to identify the connection, and `sessionId` in JSON-RPC message bodies to identify sessions. A single connection may host multiple sessions. The single GET stream delivers messages for all sessions, and clients demux by the `sessionId` field in each message. +ACP uses `Acp-Connection-Id` in HTTP headers to identify the connection, and `Acp-Session-Id` (plus the `sessionId` JSON-RPC field) to identify sessions. A single connection may host multiple sessions. The connection-scoped GET stream delivers connection-level messages; each session-scoped GET stream delivers messages for exactly one session. ### Why add WebSocket support? @@ -352,14 +369,14 @@ By inspecting the `Upgrade: websocket` header. This is standard HTTP behavior. ### Can a client have multiple sessions on one connection? -Yes. A client may call `session/new` multiple times within a single `Acp-Connection-Id`. Each returns a distinct `sessionId` in the response body. All messages for all sessions are delivered on the single GET stream. The client demuxes messages by the `sessionId` field in each JSON-RPC message. +Yes. A client may call `session/new` multiple times within a single `Acp-Connection-Id`. Each returns a distinct `sessionId` in the response body (delivered on the connection-scoped GET stream). For each session, the client opens a separate session-scoped GET stream using `Acp-Connection-Id` + `Acp-Session-Id`. ### What alternative approaches did you consider, and why did you settle on this one? - **Per-request SSE streams (like MCP)**: Rejected — creates too many long-lived connections, complicates load balancing, and wastes resources. - **Separate endpoints** (`/acp/http`, `/acp/ws`): Rejected — single endpoint is simpler; WebSocket upgrade is natural HTTP. - **WebSocket only**: Rejected — doesn't work through all proxies. -- **Session-scoped GET streams**: Rejected — still creates multiple long-lived connections per client. Connection-scoped stream with JSON-RPC demuxing is simpler. +- **Single connection-scoped GET stream with JSON-RPC demuxing**: Rejected — forces both server and client to parse JSON-RPC bodies to route by session, couples all sessions' backpressure together, and makes per-session resume/reconnect awkward. Splitting into a connection-scoped stream plus per-session streams keeps all session-level routing on HTTP headers. ### How does this interact with authentication? @@ -371,7 +388,7 @@ Clients SHOULD include it on all requests after initialization. Not yet implemen ### Why require HTTP/2? -HTTP/2 provides multiplexing, allowing many concurrent POST requests alongside the long-lived GET stream on a single TCP connection. This is essential for efficient operation with the single-stream model. HTTP/1.1 would require separate TCP connections for each concurrent POST, defeating the efficiency gains. +HTTP/2 provides multiplexing, allowing many concurrent POST requests alongside the long-lived GET streams (one connection-scoped plus one per active session) on a single TCP connection. This is essential for efficient operation with the long-lived-stream model. HTTP/1.1 would require separate TCP connections for each concurrent POST and each GET stream, defeating the efficiency gains. ## Revision history @@ -379,3 +396,4 @@ HTTP/2 provides multiplexing, allowing many concurrent POST requests alongside t - **2026-04-01**: Introduced a two-header identity model: `Acp-Connection-Id` (returned at `initialize`, binds to the connection) and `Acp-Session-Id` (returned at `session/new`, scopes to a session). This addresses feedback that the original single `Acp-Session-Id` conflated transport binding with ACP session identity, and enables session-scoped GET listener streams for targeted server-to-client event delivery. Removed connection-scoped GET streams — all GET SSE listeners now require both `Acp-Connection-Id` and `Acp-Session-Id`. - **2026-04-15**: Minor edits - **2026-04-23**: Major revision to single long-lived GET stream model. Changed from per-request SSE streams to a single connection-scoped GET stream for all server→client messages. POST requests (except `initialize`) now return 202 Accepted immediately. `initialize` returns 200 OK with JSON response body. Required HTTP/2 for multiplexing. This change makes the HTTP usage more similar to WebSocket and supports better the bidirectional nature of ACP. +- **2026-05-04**: Split the single GET stream into two: a connection-scoped stream (GET with `Acp-Connection-Id`) for connection-level messages such as responses to `session/new` and `session/load`, and session-scoped streams (GET with `Acp-Connection-Id` + `Acp-Session-Id`) for session updates, server-to-client requests like `request_permission`, and responses to session-scoped POSTs. Routing happens on HTTP headers rather than JSON-RPC body inspection; per-session streams have independent lifetimes. diff --git a/docs/rfds/updates.mdx b/docs/rfds/updates.mdx index 4c9b99632..f0f7d8e6f 100644 --- a/docs/rfds/updates.mdx +++ b/docs/rfds/updates.mdx @@ -6,6 +6,48 @@ rss: true This page tracks lifecycle changes for ACP Requests for Dialog. For broader ACP announcements, see [Updates](/updates). + +## Logout Method RFD moves to Completed + +The RFD for the `logout` method has been stabilized and is now a part of the protocol. Please review the [documentation](/protocol/authentication#logging-out) for more information. + + + + +## Additional Directories RFD moves to Preview stage + +The RFD for allowing clients to specify additional workspace roots for session lifecycle requests has been moved to Preview stage. Please review the [RFD](/rfds/additional-directories) for more information on the current proposal and provide feedback before the feature is stabilized. + + + + +## Logout Method RFD moves to Preview stage + +The RFD for adding a `logout` method to the protocol has been moved to Preview stage. Please review the [RFD](/rfds/logout-method) for more information on the current proposal and provide feedback before the feature is stabilized. + + + + +## Rust SDK based on SACP RFD moves to Preview stage + +The RFD for basing the Rust SDK on SACP has been moved to Preview stage now that the initial crate import has been upstreamed to [agentclientprotocol/rust-sdk](https://github.com/agentclientprotocol/rust-sdk). Please review the [RFD](/rfds/rust-sdk-v1) for more information on the current proposal and provide feedback before the SDK is stabilized as 1.0. + + + + +## model_config Category RFD moves to Draft + +The RFD for the `model_config` category been moved to Draft stage. Please review the [RFD](/rfds/model-config-category) for more information on the current proposal and provide feedback before the feature is stabilized. + + + + +## v2 Prompting RFD moves to Draft + +The RFD for how the prompt lifecycle will work in v2 of the protocol been moved to Draft stage. Please review the [RFD](/rfds/v2/prompt) for more information on the current proposal and provide feedback before the feature is stabilized. + + + ## session/close RFD moves to Completed diff --git a/docs/rfds/v2/overview.md b/docs/rfds/v2/overview.md new file mode 100644 index 000000000..081dd74a4 --- /dev/null +++ b/docs/rfds/v2/overview.md @@ -0,0 +1,87 @@ +--- +title: "ACP v2 Proposal" +--- + +Author(s): [@benbrandt](https://github.com/benbrandt) + +This is a tracking RFD for the collection of RFDs that require breaking changes to the protocol and should make up ACP v2. + +## Elevator pitch + +> What are you proposing to change? + +With ACP, we aim to move fast while keeping breaking changes to a minimum. However, we've gotten to a point where there are enough changes we would like to do that would benefit from some core redesigns that will allow for extending the protocol with new features more easily. + +We've also managed to add new features that has led to learnings that would benefit from consolidation and alignment in other areas of the protocol to smooth things out and make things more consistent. + +## Status quo + +> How do things work today and what problems does this cause? Why would we change things? + +We have had a fairly successful time adding new features via new capabilities and adding in new features in a non-breaking way. But some of the learnings we have made will require breaking changes, and it feels like there are enough of these built up, or RFDs we are stuck due to required changes that now is a good time to do so. + +## What we propose to do about it + +> What are you proposing to improve the situation? + +### Current Draft RFDs + +Current RFDs accepted as Drafts that are targeting v2 release + +- [New Prompt Lifecycle](./prompt.md) +- [Message IDs](../message-id.md) + - [Fork from specified IDs](../session-fork.mds) +- [Remote Transports](../streamable-http-websocket-transport.mdx) + +Other RFDs will progress separately and are not dependent on breaking changes (specifically the new prompt lifecycle) and can land in either or both v1 and v2. + +### RFDs to be Written + +Changes under consideration that still need to be drafted or moved to draft: + +- Capabilities: clean up naming and organization, as well as make some more capabilities required. +- Enum variant extension: Same as session config categories: \_ for extension, preserve non-underscore for future variants +- Streaming/Non-streaming consistency: Offer both options for both messages and tool calls + - Also Terminal Output type for streaming terminal output from an agent + - Expand diff types +- JSON-RPC Batch messages: clearer guidance on how SDK support should work for these +- Truncate/Edit support +- session/new changes: + - Providing starting message history + - Response can provide available commands + - Potentially config options +- Remove session modes and (unstable) session models. These are replaces by session config options +- Plan variants +- Subagent support + +## Shiny future + +> How will things will play out once this feature exists? + +There is a lof of work to do, especially on the SDK side, to support both versions, but it is likely that we should be able to allow Agents specifically to target v2 apis and gracefully fallback to v1 messages for v1 clients, to avoid huge support issues. + +However, once all of this work is in place, it should be much easier to make additional breaking changes in the future when necessary, we've been kind of letting this build up given the effort required for the entire ecosystem, but the ACP maintainers will be charting a course forward to make this as smooth as possible! + +## Implementation details and plan + +> Tell me more about your implementation. What is your detailed implementation plan? + +### v2 + v1 Schema publishing + +I have created a [draft of the v2 schema](https://github.com/agentclientprotocol/agent-client-protocol/pull/1099), which is currently a direct duplicate of v1. + +This also has the necessary conversion types that are needed for Rust at least to convert between the two. But this has a nice side-effect of a clear diff of how the schema will change and also what conversion is necessary. So the plan is to start proposing draft RFDs with the relevant schema changes where possible for approval. + +Once we have more pieces in place, we can start publishing both schemas to assist SDK developers to start figuring out how to support this. **This should be done in an opt-in, off by default, clearly labeled unstable way for SDK consumers**. There will likely be bumps as we figure out the necessary plumbing and we shouldn't be shipping v2 in production without feature flags prior to a more stable release as we align all of the necessary pieces. + +### SDK Support + +With the needed breaking changes, as much as possible I am targeting having a consistent API surface for Agents, since they will want to target v2 apis but still support v1 clients. Because of how the version negotiation works, if we can achieve the same thing for clients that will be great, but if not, they will at least be provided clear version entrypoints. + +## Frequently asked questions + +> What questions have arisen over the course of authoring this document or during subsequent discussions? + +## Revision history + +2026-05-06: Initial draft diff --git a/docs/rfds/v2-prompt.mdx b/docs/rfds/v2/prompt.mdx similarity index 100% rename from docs/rfds/v2-prompt.mdx rename to docs/rfds/v2/prompt.mdx diff --git a/docs/updates.mdx b/docs/updates.mdx index 9063b1c31..b4d7f1471 100644 --- a/docs/updates.mdx +++ b/docs/updates.mdx @@ -6,6 +6,17 @@ rss: true This page is for larger ACP announcements and project updates. For lifecycle changes to Requests for Dialog, see [RFD Updates](/rfds/updates). + +## Logout Method is Stabilized + +The Logout Method RFD has moved to Completed and the `logout` method is stabilized. + +This gives clients a standard way to end an authenticated state and let users authenticate again without restarting the ACP connection. + +[Read the full announcement](/announcements/logout-method-stabilized). + + + ## Session Close is Stabilized diff --git a/docs/v2-changes.md b/docs/v2-changes.md deleted file mode 100644 index 9f76a8e2b..000000000 --- a/docs/v2-changes.md +++ /dev/null @@ -1,9 +0,0 @@ -# Proposal for changes in an ACP v2 - -A WIP document to keep track of ideas and proposals for breaking changes that would require a version bump in the protocol. - -## Proposed Changes - -- Make `clientInfo` and `agentInfo` required in the `initialize` request. - -## Agreed on Changes diff --git a/package-lock.json b/package-lock.json index 5df9caca8..cfe50bb62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "license": "Apache-2.0", "devDependencies": { - "mint": "^4.2.531", + "mint": "^4.2.568", "prettier": "^3.8.3" } }, @@ -907,6 +907,19 @@ } } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1049,18 +1062,19 @@ } }, "node_modules/@mintlify/cli": { - "version": "4.0.1134", - "resolved": "https://registry.npmjs.org/@mintlify/cli/-/cli-4.0.1134.tgz", - "integrity": "sha512-BTDUtv15RiqyN9ci/4zPKKpYWdnSvR57WAAlWXxCBCk2nNMYMKBTSVCmmJ91CriYOyUrXrKXrAI1UMiWBrWvzQ==", + "version": "4.0.1171", + "resolved": "https://registry.npmjs.org/@mintlify/cli/-/cli-4.0.1171.tgz", + "integrity": "sha512-MblZzFDmHXU8wYy1ejA/FdZXCwcuHGLtAPoi6QnF84fps7HYZEzk2Kjsoepg4rNPIoxOgcj6dPG4bP35O0hPsA==", "dev": true, "license": "Elastic-2.0", "dependencies": { "@inquirer/prompts": "7.9.0", - "@mintlify/common": "1.0.865", - "@mintlify/link-rot": "3.0.1043", - "@mintlify/prebuild": "1.0.1008", - "@mintlify/previewing": "4.0.1069", - "@mintlify/validation": "0.1.676", + "@mintlify/common": "1.0.900", + "@mintlify/link-rot": "3.0.1079", + "@mintlify/models": "0.0.310", + "@mintlify/prebuild": "1.0.1044", + "@mintlify/previewing": "4.0.1105", + "@mintlify/validation": "0.1.706", "adm-zip": "0.5.16", "chalk": "5.2.0", "color": "4.2.3", @@ -1069,16 +1083,16 @@ "fs-extra": "11.2.0", "ink": "6.3.0", "inquirer": "12.3.0", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "mdast-util-mdx-jsx": "3.2.0", - "open": "^8.4.2", - "openid-client": "^6.8.2", + "open": "8.4.2", + "openid-client": "6.8.2", "posthog-node": "5.17.2", "react": "19.2.3", "semver": "7.7.2", "unist-util-visit": "5.0.0", "yargs": "17.7.1", - "zod": "^4.3.6" + "zod": "4.3.6" }, "bin": { "mint": "bin/index.js", @@ -1088,22 +1102,22 @@ "node": ">=18.0.0" }, "optionalDependencies": { - "keytar": "^7.9.0" + "keytar": "7.9.0" } }, "node_modules/@mintlify/common": { - "version": "1.0.865", - "resolved": "https://registry.npmjs.org/@mintlify/common/-/common-1.0.865.tgz", - "integrity": "sha512-p+mDIOwdtSGhgiRvr3mVNBT/PeXB3x2klkmX10SmRdePoyKheDtCqwao67f+4Av2bOeCUX3nti8Ccz6XTW/4BQ==", + "version": "1.0.900", + "resolved": "https://registry.npmjs.org/@mintlify/common/-/common-1.0.900.tgz", + "integrity": "sha512-1Jf6ThyciGksJMv+WNY6Re1GjNkngCw+A0qptybov1112KJwJmIHzaEFNh4HIugZn7hefhbiXRJLtnbCGFCRhA==", "dev": true, "license": "ISC", "dependencies": { "@asyncapi/parser": "3.4.0", "@asyncapi/specs": "6.8.1", - "@mintlify/mdx": "^3.0.4", - "@mintlify/models": "0.0.296", - "@mintlify/openapi-parser": "^0.0.8", - "@mintlify/validation": "0.1.676", + "@mintlify/mdx": "3.0.4", + "@mintlify/models": "0.0.310", + "@mintlify/openapi-parser": "0.0.8", + "@mintlify/validation": "0.1.706", "@sindresorhus/slugify": "2.2.0", "@types/mdast": "4.0.4", "acorn": "8.11.2", @@ -1117,7 +1131,7 @@ "hast-util-to-text": "4.0.2", "hex-rgb": "5.0.0", "ignore": "7.0.5", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "lodash": "4.18.1", "mdast-util-from-markdown": "2.0.2", "mdast-util-gfm": "3.0.0", @@ -1127,7 +1141,7 @@ "micromark-extension-mdx-jsx": "3.0.1", "micromark-extension-mdxjs": "3.0.0", "openapi-types": "12.1.3", - "postcss": "8.5.6", + "postcss": "8.5.14", "rehype-stringify": "10.0.1", "remark": "15.0.1", "remark-frontmatter": "5.0.0", @@ -1137,8 +1151,8 @@ "remark-parse": "11.0.0", "remark-rehype": "11.1.1", "remark-stringify": "11.0.0", - "sucrase": "^3.34.0", - "tailwindcss": "^3.4.17", + "sucrase": "3.34.0", + "tailwindcss": "3.4.17", "unified": "11.0.5", "unist-builder": "4.0.0", "unist-util-map": "4.0.0", @@ -1195,6 +1209,31 @@ "react-dom": "^18.3.1" } }, + "node_modules/@mintlify/common/node_modules/@mintlify/mdx/node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/@mintlify/common/node_modules/@mintlify/mdx/node_modules/mdast-util-gfm": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", @@ -1240,6 +1279,25 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/@mintlify/common/node_modules/@mintlify/mdx/node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/@mintlify/common/node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", @@ -1496,6 +1554,31 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/@mintlify/common/node_modules/mdast-util-mdx-jsx/node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/@mintlify/common/node_modules/next-mdx-remote-client": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/next-mdx-remote-client/-/next-mdx-remote-client-1.1.7.tgz", @@ -1560,18 +1643,18 @@ } }, "node_modules/@mintlify/link-rot": { - "version": "3.0.1043", - "resolved": "https://registry.npmjs.org/@mintlify/link-rot/-/link-rot-3.0.1043.tgz", - "integrity": "sha512-5Bk5aO/fmcVlmCG89A4hd/8YH7yW1A1tTkEPI9Dbu/HzG6gQSegya4FU7jplbx6+y/GBleK1/Du91xvi4FZVHA==", + "version": "3.0.1079", + "resolved": "https://registry.npmjs.org/@mintlify/link-rot/-/link-rot-3.0.1079.tgz", + "integrity": "sha512-iJZbw+E6vb8WQ81/gCeQ4fcndV8S6h82I7FIQ0q7CevAl1o+WhDMNdf3zNM+nlsjyPO99UZJY9KuJO2ayETyTA==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "@mintlify/common": "1.0.865", - "@mintlify/models": "0.0.296", - "@mintlify/prebuild": "1.0.1008", - "@mintlify/previewing": "4.0.1069", - "@mintlify/scraping": "4.0.522", - "@mintlify/validation": "0.1.676", + "@mintlify/common": "1.0.900", + "@mintlify/models": "0.0.310", + "@mintlify/prebuild": "1.0.1044", + "@mintlify/previewing": "4.0.1105", + "@mintlify/scraping": "4.0.764", + "@mintlify/validation": "0.1.706", "fs-extra": "11.1.0", "unist-util-visit": "4.1.2" }, @@ -1647,13 +1730,13 @@ } }, "node_modules/@mintlify/models": { - "version": "0.0.296", - "resolved": "https://registry.npmjs.org/@mintlify/models/-/models-0.0.296.tgz", - "integrity": "sha512-VwBsKkS9zWLIfGxRzb7op5GkvtsdRp8+EbICMVBEHwlj+AGir8frGOvNC1fOiyqf+mYj/IJrP6t9y3qFPqR8hg==", + "version": "0.0.310", + "resolved": "https://registry.npmjs.org/@mintlify/models/-/models-0.0.310.tgz", + "integrity": "sha512-v0TXVc2jmFxjkYYQZiZbFkFxgMaQD7En3UjyxRW9kssP4xMOl7yaaxIm9+vVS8/TUTcvMv6EXD6Uhis7LXk7UQ==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "axios": "1.15.0", + "axios": "1.16.1", "openapi-types": "12.1.3" }, "engines": { @@ -1697,90 +1780,34 @@ } }, "node_modules/@mintlify/prebuild": { - "version": "1.0.1008", - "resolved": "https://registry.npmjs.org/@mintlify/prebuild/-/prebuild-1.0.1008.tgz", - "integrity": "sha512-LpTYAB4ORpARBzzl2nN0ZxqQJWMauANs+CJQgzF/DNFO/LGAdGdCsXXuOT4lukdnU9BfKOVz9G72e05LYdQJDg==", + "version": "1.0.1044", + "resolved": "https://registry.npmjs.org/@mintlify/prebuild/-/prebuild-1.0.1044.tgz", + "integrity": "sha512-oqXM7fkfTdDdTT27ACxbf3jRi/xoj7YwV91ZQFgh3rS3NQ4fIiqKRQQgPAqkxL00fIEYYe6/74fpNAUuPvmc0g==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "@mintlify/common": "1.0.865", - "@mintlify/openapi-parser": "^0.0.8", - "@mintlify/scraping": "4.0.729", - "@mintlify/validation": "0.1.676", + "@mintlify/common": "1.0.900", + "@mintlify/openapi-parser": "0.0.8", + "@mintlify/scraping": "4.0.764", + "@mintlify/validation": "0.1.706", "chalk": "5.3.0", "favicons": "7.2.0", "front-matter": "4.0.2", "fs-extra": "11.1.0", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "openapi-types": "12.1.3", "sharp": "0.33.5", "sharp-ico": "0.1.5", "unist-util-visit": "4.1.2", - "uuid": "11.1.0" - } - }, - "node_modules/@mintlify/prebuild/node_modules/@mintlify/scraping": { - "version": "4.0.729", - "resolved": "https://registry.npmjs.org/@mintlify/scraping/-/scraping-4.0.729.tgz", - "integrity": "sha512-H6TN+R2Y1j20+1F1zldjX8qhoLBUztxpT3kW5DOzz+nYTIg0Vs2KlKeQ8lK4dBubp6bPNZDavP/v2pM94nTQlQ==", - "dev": true, - "license": "Elastic-2.0", - "dependencies": { - "@mintlify/common": "1.0.865", - "@mintlify/openapi-parser": "^0.0.8", - "fs-extra": "11.1.1", - "hast-util-to-mdast": "10.1.0", - "js-yaml": "4.1.0", - "mdast-util-mdx-jsx": "3.1.3", - "neotraverse": "0.6.18", - "puppeteer": "22.14.0", - "rehype-parse": "9.0.1", - "remark-gfm": "4.0.0", - "remark-mdx": "3.0.1", - "remark-parse": "11.0.0", - "remark-stringify": "11.0.0", - "unified": "11.0.5", - "unist-util-visit": "5.0.0", - "yargs": "17.7.1", - "zod": "3.24.0" - }, - "bin": { - "mintlify-scrape": "bin/cli.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@mintlify/prebuild/node_modules/@mintlify/scraping/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" + "uuid": "11.1.1" } }, - "node_modules/@mintlify/prebuild/node_modules/@mintlify/scraping/node_modules/unist-util-visit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", - "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "node_modules/@mintlify/prebuild/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } + "license": "MIT" }, "node_modules/@mintlify/prebuild/node_modules/chalk": { "version": "5.3.0", @@ -1810,40 +1837,14 @@ "node": ">=14.14" } }, - "node_modules/@mintlify/prebuild/node_modules/mdast-util-mdx-jsx": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", - "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mintlify/prebuild/node_modules/remark-mdx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", - "integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==", + "node_modules/@mintlify/prebuild/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", "dev": true, "license": "MIT", "dependencies": { - "mdast-util-mdx": "^3.0.0", - "micromark-extension-mdxjs": "^3.0.0" + "@types/unist": "^2.0.0" }, "funding": { "type": "opencollective", @@ -1866,28 +1867,7 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@mintlify/prebuild/node_modules/unist-util-visit/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@mintlify/prebuild/node_modules/unist-util-visit/node_modules/unist-util-is": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", - "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mintlify/prebuild/node_modules/unist-util-visit/node_modules/unist-util-visit-parents": { + "node_modules/@mintlify/prebuild/node_modules/unist-util-visit-parents": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", @@ -1902,26 +1882,16 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@mintlify/prebuild/node_modules/zod": { - "version": "3.24.0", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.0.tgz", - "integrity": "sha512-Hz+wiY8yD0VLA2k/+nsg2Abez674dDGTai33SwNvMPuf9uIrBC9eFgIMQxBBbHFxVXi8W+5nX9DcAh9YNSQm/w==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@mintlify/previewing": { - "version": "4.0.1069", - "resolved": "https://registry.npmjs.org/@mintlify/previewing/-/previewing-4.0.1069.tgz", - "integrity": "sha512-jLA5oNf5uXdWS8t5q+Fdb3FUkIi5QTWgZrHUZWuZ1Ec1WZYnwsd5j+05aSBpLr6dD5zEGWfSl6M/xSBXM2XQzA==", + "version": "4.0.1105", + "resolved": "https://registry.npmjs.org/@mintlify/previewing/-/previewing-4.0.1105.tgz", + "integrity": "sha512-/wcdC0QlEviyTHY5yIOJBSrRGyhc8+1qPkeMOlbkL1wt9OZUK9Cs5S8HrDFvUFLgirV78i3OwU3ISXuXoywiPw==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "@mintlify/common": "1.0.865", - "@mintlify/prebuild": "1.0.1008", - "@mintlify/validation": "0.1.676", + "@mintlify/common": "1.0.900", + "@mintlify/prebuild": "1.0.1044", + "@mintlify/validation": "0.1.706", "adm-zip": "0.5.16", "better-opn": "3.0.2", "chalk": "5.2.0", @@ -1933,11 +1903,11 @@ "ink": "6.3.0", "ink-spinner": "5.0.0", "is-online": "10.0.0", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "openapi-types": "12.1.3", "react": "19.2.3", "socket.io": "4.8.0", - "tar": "6.1.15", + "tar": "7.5.15", "unist-util-visit": "4.1.2", "yargs": "17.7.1" }, @@ -2013,17 +1983,17 @@ } }, "node_modules/@mintlify/scraping": { - "version": "4.0.522", - "resolved": "https://registry.npmjs.org/@mintlify/scraping/-/scraping-4.0.522.tgz", - "integrity": "sha512-PL2k52WT5S5OAgnT2K13bP7J2El6XwiVvQlrLvxDYw5KMMV+y34YVJI8ZscKb4trjitWDgyK0UTq2KN6NQgn6g==", + "version": "4.0.764", + "resolved": "https://registry.npmjs.org/@mintlify/scraping/-/scraping-4.0.764.tgz", + "integrity": "sha512-bnNCj+lb9sPuZ/WaUsNHPxhfSOzBywi9dM9430vP2cg8FfqHsasjJuxdzk9NBhYcaI3R7rGFu2DMetZGV7k/jw==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "@mintlify/common": "1.0.661", - "@mintlify/openapi-parser": "^0.0.8", + "@mintlify/common": "1.0.900", + "@mintlify/openapi-parser": "0.0.8", "fs-extra": "11.1.1", "hast-util-to-mdast": "10.1.0", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "mdast-util-mdx-jsx": "3.1.3", "neotraverse": "0.6.18", "puppeteer": "22.14.0", @@ -2035,7 +2005,7 @@ "unified": "11.0.5", "unist-util-visit": "5.0.0", "yargs": "17.7.1", - "zod": "3.21.4" + "zod": "3.24.0" }, "bin": { "mintlify-scrape": "bin/cli.js" @@ -2044,493 +2014,25 @@ "node": ">=18.0.0" } }, - "node_modules/@mintlify/scraping/node_modules/@floating-ui/react-dom": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", - "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "node_modules/@mintlify/scraping/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@floating-ui/dom": "^1.7.6" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/common": { - "version": "1.0.661", - "resolved": "https://registry.npmjs.org/@mintlify/common/-/common-1.0.661.tgz", - "integrity": "sha512-/Hdiblzaomp+AWStQ4smhVMgesQhffzQjC9aYBnmLReNdh2Js+ccQFUaWL3TNIxwiS2esaZvsHSV/D+zyRS3hg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@asyncapi/parser": "3.4.0", - "@mintlify/mdx": "^3.0.4", - "@mintlify/models": "0.0.255", - "@mintlify/openapi-parser": "^0.0.8", - "@mintlify/validation": "0.1.555", - "@sindresorhus/slugify": "2.2.0", - "@types/mdast": "4.0.4", - "acorn": "8.11.2", - "acorn-jsx": "5.3.2", - "color-blend": "4.0.0", - "estree-util-to-js": "2.0.0", - "estree-walker": "3.0.3", - "front-matter": "4.0.2", - "hast-util-from-html": "2.0.3", - "hast-util-to-html": "9.0.4", - "hast-util-to-text": "4.0.2", - "hex-rgb": "5.0.0", - "ignore": "7.0.5", - "js-yaml": "4.1.0", - "lodash": "4.17.21", - "mdast-util-from-markdown": "2.0.2", - "mdast-util-gfm": "3.0.0", - "mdast-util-mdx": "3.0.0", - "mdast-util-mdx-jsx": "3.1.3", - "micromark-extension-gfm": "3.0.0", - "micromark-extension-mdx-jsx": "3.0.1", - "micromark-extension-mdxjs": "3.0.0", - "openapi-types": "12.1.3", - "postcss": "8.5.6", - "rehype-stringify": "10.0.1", - "remark": "15.0.1", - "remark-frontmatter": "5.0.0", - "remark-gfm": "4.0.0", - "remark-math": "6.0.0", - "remark-mdx": "3.1.0", - "remark-parse": "11.0.0", - "remark-rehype": "11.1.1", - "remark-stringify": "11.0.0", - "tailwindcss": "3.4.4", - "unified": "11.0.5", - "unist-builder": "4.0.0", - "unist-util-map": "4.0.0", - "unist-util-remove": "4.0.0", - "unist-util-remove-position": "5.0.0", - "unist-util-visit": "5.0.0", - "unist-util-visit-parents": "6.0.1", - "vfile": "6.0.3" + "engines": { + "node": ">=14.14" } }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/common/node_modules/remark-mdx": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", - "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdast-util-mdx": "^3.0.0", - "micromark-extension-mdxjs": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/mdx": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@mintlify/mdx/-/mdx-3.0.4.tgz", - "integrity": "sha512-tJhdpnM5ReJLNJ2fuDRIEr0zgVd6id7/oAIfs26V46QlygiLsc8qx4Rz3LWIX51rUXW/cfakjj0EATxIciIw+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/transformers": "^3.11.0", - "@shikijs/twoslash": "^3.12.2", - "arktype": "^2.1.26", - "hast-util-to-string": "^3.0.1", - "mdast-util-from-markdown": "^2.0.2", - "mdast-util-gfm": "^3.1.0", - "mdast-util-mdx-jsx": "^3.2.0", - "mdast-util-to-hast": "^13.2.0", - "next-mdx-remote-client": "^1.0.3", - "rehype-katex": "^7.0.1", - "remark-gfm": "^4.0.0", - "remark-math": "^6.0.0", - "remark-smartypants": "^3.0.2", - "shiki": "^3.11.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0" - }, - "peerDependencies": { - "@radix-ui/react-popover": "^1.1.15", - "react": "^18.3.1", - "react-dom": "^18.3.1" - } - }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/mdx/node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/mdx/node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/models": { - "version": "0.0.255", - "resolved": "https://registry.npmjs.org/@mintlify/models/-/models-0.0.255.tgz", - "integrity": "sha512-LIUkfA7l7ypHAAuOW74ZJws/NwNRqlDRD/U466jarXvvSlGhJec/6J4/I+IEcBvWDnc9anLFKmnGO04jPKgAsg==", - "dev": true, - "license": "Elastic-2.0", - "dependencies": { - "axios": "1.10.0", - "openapi-types": "12.1.3" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/@mintlify/validation": { - "version": "0.1.555", - "resolved": "https://registry.npmjs.org/@mintlify/validation/-/validation-0.1.555.tgz", - "integrity": "sha512-11QVUReL4N5u8wSCgZt4RN7PA0jYQoMEBZ5IrUp5pgb5ZJBOoGV/vPsQrxPPa1cxsUDAuToNhtGxRQtOav/w8w==", - "dev": true, - "license": "Elastic-2.0", - "dependencies": { - "@mintlify/mdx": "^3.0.4", - "@mintlify/models": "0.0.255", - "arktype": "2.1.27", - "js-yaml": "4.1.0", - "lcm": "0.0.3", - "lodash": "4.17.21", - "object-hash": "3.0.0", - "openapi-types": "12.1.3", - "uuid": "11.1.0", - "zod": "3.21.4", - "zod-to-json-schema": "3.20.4" - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-popover": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", - "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/axios": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", - "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@mintlify/scraping/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/@mintlify/scraping/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@mintlify/scraping/node_modules/mdast-util-mdx-jsx": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", - "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", + "node_modules/@mintlify/scraping/node_modules/mdast-util-mdx-jsx": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.3.tgz", + "integrity": "sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2552,65 +2054,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@mintlify/scraping/node_modules/next-mdx-remote-client": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/next-mdx-remote-client/-/next-mdx-remote-client-1.1.7.tgz", - "integrity": "sha512-12Ap5Z/tFIETMXFSBTH2IFEhJAso7MvOJ5ICyesA4q6FM4vtAcmb+4ZKa4tV1IVQJLBVqOhaEfIESZzdwjmrQQ==", - "dev": true, - "license": "MPL 2.0", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@mdx-js/mdx": "^3.1.1", - "@mdx-js/react": "^3.1.1", - "remark-mdx-remove-esm": "^1.3.1", - "serialize-error": "^13.0.1", - "vfile": "^6.0.3", - "vfile-matter": "^5.0.1" - }, - "engines": { - "node": ">=20.9.0" - }, - "peerDependencies": { - "react": ">= 18.3.0 < 19.0.0", - "react-dom": ">= 18.3.0 < 19.0.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@mintlify/scraping/node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, "node_modules/@mintlify/scraping/node_modules/remark-mdx": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz", @@ -2626,145 +2069,54 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@mintlify/scraping/node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/tailwindcss": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", - "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.0", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.0", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@mintlify/scraping/node_modules/tailwindcss/node_modules/postcss-load-config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.0.0", - "yaml": "^2.3.4" - }, - "engines": { - "node": ">= 14" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/@mintlify/scraping/node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, "node_modules/@mintlify/scraping/node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@mintlify/scraping/node_modules/zod-to-json-schema": { - "version": "3.20.4", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.20.4.tgz", - "integrity": "sha512-Un9+kInJ2Zt63n6Z7mLqBifzzPcOyX+b+Exuzf7L1+xqck9Q2EPByyTRduV3kmSPaXaRer1JCsucubpgL1fipg==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.20.0" + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.0.tgz", + "integrity": "sha512-Hz+wiY8yD0VLA2k/+nsg2Abez674dDGTai33SwNvMPuf9uIrBC9eFgIMQxBBbHFxVXi8W+5nX9DcAh9YNSQm/w==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@mintlify/validation": { - "version": "0.1.676", - "resolved": "https://registry.npmjs.org/@mintlify/validation/-/validation-0.1.676.tgz", - "integrity": "sha512-aPJVM9R2Dw0MDBWkN6BrziIH2jEdxU4MLtyvLArmB9gz7tPquPzzOWSQqafQM5QEsnPhRxRzsbteunXfDWFzFQ==", + "version": "0.1.706", + "resolved": "https://registry.npmjs.org/@mintlify/validation/-/validation-0.1.706.tgz", + "integrity": "sha512-eAij8SDzz9r8wFsrQmaYSR1cixhUgMq4Sh0LdzqTAL+O4v7u7sPgPgq07lpIxHtwHEiBk8JI3mfHjafQLn4leg==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "@mintlify/mdx": "^3.0.4", - "@mintlify/models": "0.0.296", + "@mintlify/mdx": "3.0.4", + "@mintlify/models": "0.0.310", "arktype": "2.1.27", - "js-yaml": "4.1.0", + "js-yaml": "4.1.1", "lcm": "0.0.3", "lodash": "4.18.1", "neotraverse": "0.6.18", "object-hash": "3.0.0", "openapi-types": "12.1.3", - "uuid": "11.1.0", + "uuid": "11.1.1", "zod": "3.24.0", "zod-to-json-schema": "3.20.4" } }, + "node_modules/@mintlify/validation/node_modules/@ark/schema": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@ark/schema/-/schema-0.56.0.tgz", + "integrity": "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ark/util": "0.56.0" + } + }, + "node_modules/@mintlify/validation/node_modules/@ark/util": { + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/@ark/util/-/util-0.56.0.tgz", + "integrity": "sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==", + "dev": true, + "license": "MIT" + }, "node_modules/@mintlify/validation/node_modules/@floating-ui/react-dom": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", @@ -2810,6 +2162,18 @@ "react-dom": "^18.3.1" } }, + "node_modules/@mintlify/validation/node_modules/@mintlify/mdx/node_modules/arktype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arktype/-/arktype-2.2.0.tgz", + "integrity": "sha512-t54MZ7ti5BhOEvzEkgKnWvqj+UbDfWig+DHr5I34xatymPusKLS0lQpNJd8M6DzmIto2QGszHfNKoFIT8tMCZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ark/schema": "0.56.0", + "@ark/util": "0.56.0", + "arkregex": "0.0.5" + } + }, "node_modules/@mintlify/validation/node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", @@ -3041,6 +2405,16 @@ } } }, + "node_modules/@mintlify/validation/node_modules/arkregex": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/arkregex/-/arkregex-0.0.5.tgz", + "integrity": "sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ark/util": "0.56.0" + } + }, "node_modules/@mintlify/validation/node_modules/mdast-util-gfm": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", @@ -3296,9 +2670,9 @@ } }, "node_modules/@puppeteer/browsers/node_modules/tar-stream": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", - "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", "dev": true, "license": "MIT", "dependencies": { @@ -3855,9 +3229,9 @@ } }, "node_modules/@stoplight/spectral-core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.22.0.tgz", - "integrity": "sha512-4hTxMDs4TFUG4/jKjaZttA65gNuV2PCKI9+51I+J4nL6ylo17DlbW+sl6byKnBuV/85HxaV33ri5fEGlp8lTSA==", + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.23.0.tgz", + "integrity": "sha512-WvdgmiiJrjiMrcw7ByxfcYtUvAXNp2MhAfcEIXP3Mn8ZOVwyAWIsFjLlsE5zRqj0LuN8+7OQM/L+BMcHj6x/BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4188,9 +3562,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -4270,13 +3644,13 @@ } }, "node_modules/@types/node": { - "version": "25.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", - "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "version": "25.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz", + "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.19.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/react": { @@ -4339,9 +3713,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", "dev": true, "license": "ISC" }, @@ -4416,13 +3790,16 @@ } }, "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, "license": "MIT", + "dependencies": { + "debug": "4" + }, "engines": { - "node": ">= 14" + "node": ">= 6.0.0" } }, "node_modules/aggregate-error": { @@ -4767,21 +4144,22 @@ } }, "node_modules/axios": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", - "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "node_modules/b4a": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -4812,9 +4190,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", + "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -4852,9 +4230,9 @@ } }, "node_modules/bare-os": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.0.tgz", - "integrity": "sha512-JTjuZyNIDpw+GytMO4a6TK1VXdVKKJr6DRxEHasyuYyShV2deuiHJK/ahGZlebc+SG0/wJCB9XK8gprBGDFi/Q==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4872,9 +4250,9 @@ } }, "node_modules/bare-stream": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz", - "integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4899,9 +4277,9 @@ } }, "node_modules/bare-url": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.2.tgz", - "integrity": "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4940,9 +4318,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz", - "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", "dev": true, "license": "MIT", "engines": { @@ -5044,9 +4422,9 @@ "license": "MIT" }, "node_modules/body-parser/node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5331,13 +4709,13 @@ } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/chromium-bidi": { @@ -6532,9 +5910,9 @@ } }, "node_modules/es-toolkit": { - "version": "1.46.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.46.0.tgz", - "integrity": "sha512-IToJ6ct9OLl5zz6WsC/1vZEwfSZ7Myil+ygl5Tf30Xjn9AEkzNB4kqp2G7VUJKF1DtTx/ra5M5KLlXvzOg51BA==", + "version": "1.46.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.46.1.tgz", + "integrity": "sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==", "dev": true, "license": "MIT", "workspaces": [ @@ -6969,9 +6347,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -7233,31 +6611,12 @@ "node": ">=14.14" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -7343,9 +6702,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "dev": true, "license": "MIT", "engines": { @@ -7459,6 +6818,28 @@ "license": "MIT", "optional": true }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -8047,6 +7428,16 @@ "node": ">= 14" } }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/http2-wrapper": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", @@ -8062,17 +7453,17 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", + "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6" } }, "node_modules/ico-endec": { @@ -8171,6 +7562,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -8363,9 +7766,9 @@ } }, "node_modules/ip-address": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.1.tgz", - "integrity": "sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -8523,13 +7926,13 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -9026,9 +8429,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { @@ -9119,9 +8522,9 @@ } }, "node_modules/katex": { - "version": "0.16.45", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.45.tgz", - "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==", + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", "dev": true, "funding": [ "https://opencollective.com/katex", @@ -10567,50 +9970,36 @@ } }, "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">=8" + "node": ">= 18" } }, "node_modules/mint": { - "version": "4.2.531", - "resolved": "https://registry.npmjs.org/mint/-/mint-4.2.531.tgz", - "integrity": "sha512-AxdWSgByE0OKNuapg3ruAe8mKWqBiEv+FqvTWaXt6jjyERFemd4c5B0mZ7LS0P0Qmr9IzEaeNjouwT5tp+Wx3A==", + "version": "4.2.568", + "resolved": "https://registry.npmjs.org/mint/-/mint-4.2.568.tgz", + "integrity": "sha512-kVDNpvLgJZ1AVIuVZGohc25OhtrBaikyKAd27BjH6KTzg3IU8URYYHiMSqa7zWGg0EH4OYPwPRgq3X78XkAjZA==", "dev": true, "license": "Elastic-2.0", "dependencies": { - "@mintlify/cli": "4.0.1134" + "@mintlify/cli": "4.0.1171" }, "bin": { "mint": "index.js" @@ -10626,19 +10015,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -10677,9 +10053,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -10768,9 +10144,9 @@ } }, "node_modules/node-abi": { - "version": "3.89.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", - "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "version": "3.92.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz", + "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==", "dev": true, "license": "MIT", "optional": true, @@ -11004,14 +10380,14 @@ "license": "MIT" }, "node_modules/openid-client": { - "version": "6.8.4", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.4.tgz", - "integrity": "sha512-QSw0BA08piujetEwfZsHoTrDpMEha7GDZDicQqVwX4u0ChCjefvjDB++TZ8BTg76UpwhzIQgdvvfgfl3HpCSAw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.2.tgz", + "integrity": "sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA==", "dev": true, "license": "MIT", "dependencies": { - "jose": "^6.2.2", - "oauth4webapi": "^3.8.5" + "jose": "^6.1.3", + "oauth4webapi": "^3.8.4" }, "funding": { "url": "https://github.com/sponsors/panva" @@ -11112,6 +10488,30 @@ "node": ">= 14" } }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/pac-resolver": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", @@ -11237,6 +10637,16 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -11329,9 +10739,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", "dev": true, "funding": [ { @@ -11402,9 +10812,9 @@ } }, "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", "dev": true, "funding": [ { @@ -11418,28 +10828,21 @@ ], "license": "MIT", "dependencies": { - "lilconfig": "^3.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { - "node": ">= 18" + "node": ">= 14" }, "peerDependencies": { - "jiti": ">=1.21.0", "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" + "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { - "jiti": { - "optional": true - }, "postcss": { "optional": true }, - "tsx": { - "optional": true - }, - "yaml": { + "ts-node": { "optional": true } } @@ -11604,6 +11007,30 @@ "node": ">= 14" } }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/proxy-agent/node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -13229,13 +12656,13 @@ } }, "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "^10.0.1", + "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -13258,6 +12685,16 @@ "node": ">= 14" } }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -13506,18 +12943,18 @@ } }, "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", + "glob": "7.1.6", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { @@ -13525,7 +12962,7 @@ "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" } }, "node_modules/sucrase/node_modules/commander": { @@ -13565,9 +13002,9 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, "license": "MIT", "dependencies": { @@ -13579,7 +13016,7 @@ "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.7", + "jiti": "^1.21.6", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", @@ -13588,7 +13025,7 @@ "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-load-config": "^4.0.2", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", @@ -13640,6 +13077,16 @@ "node": ">= 6" } }, + "node_modules/tailwindcss/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/tailwindcss/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -13653,23 +13100,44 @@ "node": ">=10.13.0" } }, + "node_modules/tailwindcss/node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "version": "7.5.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/tar-fs": { @@ -14080,9 +13548,9 @@ } }, "node_modules/undici-types": { - "version": "7.19.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", - "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", "dev": true, "license": "MIT" }, @@ -14421,9 +13889,9 @@ } }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -14748,9 +14216,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "dev": true, "license": "MIT", "engines": { @@ -14828,16 +14296,19 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "license": "ISC" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } }, "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "dev": true, "license": "ISC", "bin": { diff --git a/package.json b/package.json index f757ad1ee..95be49165 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "docs": "cd docs && npx mint dev" }, "devDependencies": { - "mint": "^4.2.531", + "mint": "^4.2.568", "prettier": "^3.8.3" } } diff --git a/schema/meta.json b/schema/meta.json index 8dc36e94f..bc5135b29 100644 --- a/schema/meta.json +++ b/schema/meta.json @@ -2,6 +2,7 @@ "agentMethods": { "authenticate": "authenticate", "initialize": "initialize", + "logout": "logout", "session_cancel": "session/cancel", "session_close": "session/close", "session_list": "session/list", diff --git a/schema/meta.unstable.json b/schema/meta.unstable.json index 6d1dd249a..5775e369d 100644 --- a/schema/meta.unstable.json +++ b/schema/meta.unstable.json @@ -8,6 +8,7 @@ "document_did_save": "document/didSave", "initialize": "initialize", "logout": "logout", + "mcp_message": "mcp/message", "nes_accept": "nes/accept", "nes_close": "nes/close", "nes_reject": "nes/reject", @@ -18,6 +19,7 @@ "providers_set": "providers/set", "session_cancel": "session/cancel", "session_close": "session/close", + "session_delete": "session/delete", "session_fork": "session/fork", "session_list": "session/list", "session_load": "session/load", @@ -33,6 +35,9 @@ "elicitation_create": "elicitation/create", "fs_read_text_file": "fs/read_text_file", "fs_write_text_file": "fs/write_text_file", + "mcp_connect": "mcp/connect", + "mcp_disconnect": "mcp/disconnect", + "mcp_message": "mcp/message", "session_request_permission": "session/request_permission", "session_update": "session/update", "terminal_create": "terminal/create", diff --git a/schema/meta.v2.unstable.json b/schema/meta.v2.unstable.json index 462086fd4..91985fc35 100644 --- a/schema/meta.v2.unstable.json +++ b/schema/meta.v2.unstable.json @@ -8,6 +8,7 @@ "document_did_save": "document/didSave", "initialize": "initialize", "logout": "logout", + "mcp_message": "mcp/message", "nes_accept": "nes/accept", "nes_close": "nes/close", "nes_reject": "nes/reject", @@ -18,6 +19,7 @@ "providers_set": "providers/set", "session_cancel": "session/cancel", "session_close": "session/close", + "session_delete": "session/delete", "session_fork": "session/fork", "session_list": "session/list", "session_load": "session/load", @@ -33,6 +35,9 @@ "elicitation_create": "elicitation/create", "fs_read_text_file": "fs/read_text_file", "fs_write_text_file": "fs/write_text_file", + "mcp_connect": "mcp/connect", + "mcp_disconnect": "mcp/disconnect", + "mcp_message": "mcp/message", "session_request_permission": "session/request_permission", "session_update": "session/update", "terminal_create": "terminal/create", diff --git a/schema/schema.json b/schema/schema.json index d6c327e83..adc9d2576 100644 --- a/schema/schema.json +++ b/schema/schema.json @@ -1,5 +1,27 @@ { "$defs": { + "AgentAuthCapabilities": { + "description": "Authentication-related capabilities supported by the agent.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "logout": { + "anyOf": [ + { + "$ref": "#/$defs/LogoutCapabilities" + }, + { + "type": "null" + } + ], + "description": "Whether the agent supports the logout method.\n\nBy supplying `{}` it means that the agent supports the logout method." + } + }, + "type": "object" + }, "AgentCapabilities": { "description": "Capabilities supported by the agent.\n\nAdvertised during initialization to inform the client about\navailable features and content types.\n\nSee protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)", "properties": { @@ -8,6 +30,15 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "auth": { + "allOf": [ + { + "$ref": "#/$defs/AgentAuthCapabilities" + } + ], + "default": {}, + "description": "Authentication-related capabilities supported by the agent." + }, "loadSession": { "default": false, "description": "Whether the agent supports `session/load`.", @@ -34,7 +65,8 @@ "default": { "audio": false, "embeddedContext": false, - "image": false + "image": false, + "promptVariables": false }, "description": "Prompt capabilities supported by the agent." }, @@ -220,6 +252,14 @@ ], "title": "AuthenticateResponse" }, + { + "allOf": [ + { + "$ref": "#/$defs/LogoutResponse" + } + ], + "title": "LogoutResponse" + }, { "allOf": [ { @@ -642,6 +682,15 @@ "description": "Authenticates the client using the specified authentication method.\n\nCalled when the agent requires authentication before allowing session creation.\nThe client provides the authentication method ID that was advertised during initialization.\n\nAfter successful authentication, the client can proceed to create sessions with\n`new_session` without receiving an `auth_required` error.\n\nSee protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)", "title": "AuthenticateRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/LogoutRequest" + } + ], + "description": "Logs out of the current authenticated state.\n\nAfter a successful logout, all new sessions will require authentication.\nThere is no guarantee about the behavior of already running sessions.", + "title": "LogoutRequest" + }, { "allOf": [ { @@ -1000,6 +1049,22 @@ }, "required": ["type"], "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/PromptTemplateContent" + } + ], + "description": "A template that supports variable substitution using {{variable_name}} syntax.\n\nAllows dynamic content generation by substituting variables into template strings.\nVariables are resolved at processing time and can include values from context,\nuser input, or system state.\n\nRequires the `promptVariables` prompt capability when included in prompts.", + "properties": { + "type": { + "const": "prompt_template", + "type": "string" + } + }, + "required": ["type"], + "type": "object" } ] }, @@ -1451,6 +1516,7 @@ } ], "default": { + "auth": {}, "loadSession": false, "mcpCapabilities": { "http": false, @@ -1459,7 +1525,8 @@ "promptCapabilities": { "audio": false, "embeddedContext": false, - "image": false + "image": false, + "promptVariables": false }, "sessionCapabilities": {} }, @@ -1647,6 +1714,43 @@ "x-method": "session/load", "x-side": "agent" }, + "LogoutCapabilities": { + "description": "Logout capabilities supported by the agent.\n\nBy supplying `{}` it means that the agent supports the logout method.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object" + }, + "LogoutRequest": { + "description": "Request parameters for the logout method.\n\nTerminates the current authenticated session.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object", + "x-method": "logout", + "x-side": "agent" + }, + "LogoutResponse": { + "description": "Response to the `logout` method.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object", + "x-method": "logout", + "x-side": "agent" + }, "McpCapabilities": { "description": "MCP capabilities supported by the agent", "properties": { @@ -2041,6 +2145,11 @@ "default": false, "description": "Agent supports [`ContentBlock::Image`].", "type": "boolean" + }, + "promptVariables": { + "default": false, + "description": "Agent supports prompt variables and templates in `session/prompt` requests.\n\nWhen enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`]\nin prompt requests with variable substitution support.", + "type": "boolean" } }, "type": "object" @@ -2096,6 +2205,143 @@ "x-method": "session/prompt", "x-side": "agent" }, + "PromptTemplateContent": { + "description": "A template content block that supports variable substitution.\n\nTemplates use {{variable_name}} syntax for variable placeholders that can be\nsubstituted with actual values at processing time. This enables dynamic content\ngeneration and reusable prompt templates.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "annotations": { + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ] + }, + "template": { + "description": "The template string with {{variable_name}} placeholders.", + "type": "string" + }, + "variables": { + "description": "Variables available for substitution in this template.", + "items": { + "$ref": "#/$defs/PromptVariable" + }, + "type": "array" + } + }, + "required": ["template", "variables"], + "type": "object" + }, + "PromptVariable": { + "description": "A variable that can be substituted in a prompt template.\n\nVariables define named placeholders that can be replaced with actual values\nduring template processing. They can include metadata about expected types,\ndescriptions for user interfaces, and validation constraints.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "default_value": { + "description": "Default value to use if no value is provided.", + "type": ["string", "null"] + }, + "description": { + "description": "Human-readable description of this variable.", + "type": ["string", "null"] + }, + "name": { + "description": "The variable name (used in {{variable_name}} placeholders).", + "type": "string" + }, + "required": { + "default": false, + "description": "Whether this variable is required for template processing.", + "type": "boolean" + }, + "type": { + "anyOf": [ + { + "$ref": "#/$defs/PromptVariableType" + }, + { + "type": "null" + } + ], + "description": "The expected type of this variable's value." + }, + "value": { + "description": "The current value of the variable (if set).", + "type": ["string", "null"] + } + }, + "required": ["name"], + "type": "object" + }, + "PromptVariableType": { + "description": "The expected type of a prompt variable's value.\n\nThis helps clients provide appropriate input interfaces and validation\nfor prompt variables.", + "oneOf": [ + { + "const": "string", + "description": "A string value (default if not specified).", + "type": "string" + }, + { + "const": "number", + "description": "A numeric value (integer or float).", + "type": "string" + }, + { + "const": "boolean", + "description": "A boolean value (true/false).", + "type": "string" + }, + { + "const": "date_time", + "description": "A date/time value in ISO 8601 format.", + "type": "string" + }, + { + "const": "url", + "description": "A URL or URI reference.", + "type": "string" + }, + { + "const": "email", + "description": "An email address.", + "type": "string" + }, + { + "const": "text", + "description": "A multiline text value.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "A value selected from a predefined list (enum-like).", + "properties": { + "select": { + "properties": { + "options": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["options"], + "type": "object" + } + }, + "required": ["select"], + "type": "object" + } + ] + }, "ProtocolVersion": { "description": "Protocol version identifier.\n\nThis version is only bumped for breaking changes.\nNon-breaking changes should be introduced via capabilities.", "format": "uint16", diff --git a/schema/schema.unstable.json b/schema/schema.unstable.json index b304602c4..48a14e5cb 100644 --- a/schema/schema.unstable.json +++ b/schema/schema.unstable.json @@ -27,7 +27,7 @@ "x-side": "agent" }, "AgentAuthCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication-related capabilities supported by the agent.", + "description": "Authentication-related capabilities supported by the agent.", "properties": { "_meta": { "additionalProperties": true, @@ -63,7 +63,7 @@ } ], "default": {}, - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication-related capabilities supported by the agent." + "description": "Authentication-related capabilities supported by the agent." }, "loadSession": { "default": false, @@ -77,6 +77,7 @@ } ], "default": { + "acp": false, "http": false, "sse": false }, @@ -113,7 +114,8 @@ "default": { "audio": false, "embeddedContext": false, - "image": false + "image": false, + "promptVariables": false }, "description": "Prompt capabilities supported by the agent." }, @@ -166,6 +168,15 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nNotification that a URL-based elicitation has completed.", "title": "CompleteElicitationNotification" }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpNotification" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nReceives an MCP-over-ACP notification.", + "title": "MessageMcpNotification" + }, { "allOf": [ { @@ -281,6 +292,33 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequests structured user input via a form or URL.", "title": "CreateElicitationRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/ConnectMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nOpens an MCP-over-ACP connection.", + "title": "ConnectMcpRequest" + }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nExchanges an MCP-over-ACP message.", + "title": "MessageMcpRequest" + }, + { + "allOf": [ + { + "$ref": "#/$defs/DisconnectMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCloses an MCP-over-ACP connection.", + "title": "DisconnectMcpRequest" + }, { "allOf": [ { @@ -339,18 +377,18 @@ { "allOf": [ { - "$ref": "#/$defs/SetProvidersResponse" + "$ref": "#/$defs/SetProviderResponse" } ], - "title": "SetProvidersResponse" + "title": "SetProviderResponse" }, { "allOf": [ { - "$ref": "#/$defs/DisableProvidersResponse" + "$ref": "#/$defs/DisableProviderResponse" } ], - "title": "DisableProvidersResponse" + "title": "DisableProviderResponse" }, { "allOf": [ @@ -384,6 +422,14 @@ ], "title": "ListSessionsResponse" }, + { + "allOf": [ + { + "$ref": "#/$defs/DeleteSessionResponse" + } + ], + "title": "DeleteSessionResponse" + }, { "allOf": [ { @@ -471,6 +517,14 @@ } ], "title": "ExtMethodResponse" + }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpResponse" + } + ], + "title": "MessageMcpResponse" } ], "description": "All possible responses that an agent can send to a client.\n\nThis enum is used internally for routing RPC responses. You typically won't need\nto use this directly - the responses are handled automatically by the connection.\n\nThese are responses to the corresponding `ClientRequest` variants." @@ -1108,6 +1162,15 @@ "description": "**UNSTABLE**\n\nNotification sent when a suggestion is rejected.", "title": "RejectNesNotification" }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpNotification" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nSends an MCP-over-ACP notification.", + "title": "MessageMcpNotification" + }, { "allOf": [ { @@ -1172,20 +1235,20 @@ { "allOf": [ { - "$ref": "#/$defs/SetProvidersRequest" + "$ref": "#/$defs/SetProviderRequest" } ], "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nReplaces the configuration for a provider.", - "title": "SetProvidersRequest" + "title": "SetProviderRequest" }, { "allOf": [ { - "$ref": "#/$defs/DisableProvidersRequest" + "$ref": "#/$defs/DisableProviderRequest" } ], "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDisables a provider.", - "title": "DisableProvidersRequest" + "title": "DisableProviderRequest" }, { "allOf": [ @@ -1193,7 +1256,7 @@ "$ref": "#/$defs/LogoutRequest" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLogs out of the current authenticated state.\n\nAfter a successful logout, all new sessions will require authentication.\nThere is no guarantee about the behavior of already running sessions.", + "description": "Logs out of the current authenticated state.\n\nAfter a successful logout, all new sessions will require authentication.\nThere is no guarantee about the behavior of already running sessions.", "title": "LogoutRequest" }, { @@ -1223,6 +1286,15 @@ "description": "Lists existing sessions known to the agent.\n\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\n\nThe agent should return metadata about sessions with optional filtering and pagination support.", "title": "ListSessionsRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/DeleteSessionRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDeletes an existing session from `session/list`.\n\nThis method is only available if the agent advertises the `sessionCapabilities.delete` capability.", + "title": "DeleteSessionRequest" + }, { "allOf": [ { @@ -1313,6 +1385,15 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCloses an active NES session and frees up any resources associated with it.\n\nThe agent must cancel any ongoing work and then free up any resources\nassociated with the NES session.", "title": "CloseNesRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nExchanges an MCP-over-ACP message.", + "title": "MessageMcpRequest" + }, { "allOf": [ { @@ -1416,6 +1497,22 @@ ], "title": "CreateElicitationResponse" }, + { + "allOf": [ + { + "$ref": "#/$defs/ConnectMcpResponse" + } + ], + "title": "ConnectMcpResponse" + }, + { + "allOf": [ + { + "$ref": "#/$defs/DisconnectMcpResponse" + } + ], + "title": "DisconnectMcpResponse" + }, { "allOf": [ { @@ -1423,6 +1520,14 @@ } ], "title": "ExtMethodResponse" + }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpResponse" + } + ], + "title": "MessageMcpResponse" } ], "description": "All possible responses that a client can send to an agent.\n\nThis enum is used internally for routing RPC responses. You typically won't need\nto use this directly - the responses are handled automatically by the connection.\n\nThese are responses to the corresponding `AgentRequest` variants." @@ -1559,6 +1664,50 @@ "required": ["configOptions"], "type": "object" }, + "ConnectMcpRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `mcp/connect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "acpId": { + "allOf": [ + { + "$ref": "#/$defs/McpServerAcpId" + } + ], + "description": "The ACP MCP server ID that was provided by the component declaring the MCP server." + } + }, + "required": ["acpId"], + "type": "object", + "x-method": "mcp/connect", + "x-side": "client" + }, + "ConnectMcpResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `mcp/connect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The unique identifier for this MCP-over-ACP connection." + } + }, + "required": ["connectionId"], + "type": "object", + "x-method": "mcp/connect", + "x-side": "client" + }, "Content": { "description": "Standard content block (text, images, resources).", "properties": { @@ -1664,6 +1813,22 @@ }, "required": ["type"], "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/PromptTemplateContent" + } + ], + "description": "A template that supports variable substitution using {{variable_name}} syntax.\n\nAllows dynamic content generation by substituting variables into template strings.\nVariables are resolved at processing time and can include values from context,\nuser input, or system state.\n\nRequires the `promptVariables` prompt capability when included in prompts.", + "properties": { + "type": { + "const": "prompt_template", + "type": "string" + } + }, + "required": ["type"], + "type": "object" } ] }, @@ -1906,6 +2071,41 @@ "required": ["currentModeId"], "type": "object" }, + "DeleteSessionRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for deleting an existing session from `session/list`.\n\nOnly available if the Agent supports the `sessionCapabilities.delete` capability.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "sessionId": { + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ], + "description": "The ID of the session to delete." + } + }, + "required": ["sessionId"], + "type": "object", + "x-method": "session/delete", + "x-side": "agent" + }, + "DeleteSessionResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse from deleting a session.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object", + "x-method": "session/delete", + "x-side": "agent" + }, "DidChangeDocumentNotification": { "description": "Notification sent when a file is edited.", "properties": { @@ -2106,7 +2306,7 @@ "required": ["path", "newText"], "type": "object" }, - "DisableProvidersRequest": { + "DisableProviderRequest": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/disable`.", "properties": { "_meta": { @@ -2124,7 +2324,7 @@ "x-method": "providers/disable", "x-side": "agent" }, - "DisableProvidersResponse": { + "DisableProviderResponse": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/disable`.", "properties": { "_meta": { @@ -2137,6 +2337,41 @@ "x-method": "providers/disable", "x-side": "agent" }, + "DisconnectMcpRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `mcp/disconnect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The MCP-over-ACP connection to close." + } + }, + "required": ["connectionId"], + "type": "object", + "x-method": "mcp/disconnect", + "x-side": "client" + }, + "DisconnectMcpResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `mcp/disconnect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object", + "x-method": "mcp/disconnect", + "x-side": "client" + }, "ElicitationAcceptAction": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nThe user accepted the elicitation and provided content.", "properties": { @@ -2942,13 +3177,15 @@ "auth": {}, "loadSession": false, "mcpCapabilities": { + "acp": false, "http": false, "sse": false }, "promptCapabilities": { "audio": false, "embeddedContext": false, - "image": false + "image": false, + "promptVariables": false }, "sessionCapabilities": {} }, @@ -3097,13 +3334,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nFilter sessions by the exact ordered additional workspace roots. Each path must be absolute.\n\nThis filter applies only when the field is present and non-empty. When\nomitted or empty, no additional-root filter is applied.", - "items": { - "type": "string" - }, - "type": "array" - }, "cursor": { "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", "type": ["string", "null"] @@ -3186,7 +3416,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`.", "items": { "type": "string" }, @@ -3260,7 +3490,7 @@ "x-side": "agent" }, "LogoutCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLogout capabilities supported by the agent.\n\nBy supplying `{}` it means that the agent supports the logout method.", + "description": "Logout capabilities supported by the agent.\n\nBy supplying `{}` it means that the agent supports the logout method.", "properties": { "_meta": { "additionalProperties": true, @@ -3271,7 +3501,7 @@ "type": "object" }, "LogoutRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for the logout method.\n\nTerminates the current authenticated session.", + "description": "Request parameters for the logout method.\n\nTerminates the current authenticated session.", "properties": { "_meta": { "additionalProperties": true, @@ -3284,7 +3514,7 @@ "x-side": "agent" }, "LogoutResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to the `logout` method.", + "description": "Response to the `logout` method.", "properties": { "_meta": { "additionalProperties": true, @@ -3304,6 +3534,11 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "acp": { + "default": false, + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAgent supports [`McpServer::Acp`].", + "type": "boolean" + }, "http": { "default": false, "description": "Agent supports [`McpServer::Http`].", @@ -3317,6 +3552,10 @@ }, "type": "object" }, + "McpConnectionId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for an active MCP-over-ACP connection.", + "type": "string" + }, "McpServer": { "anyOf": [ { @@ -3351,6 +3590,22 @@ "required": ["type"], "type": "object" }, + { + "allOf": [ + { + "$ref": "#/$defs/McpServerAcp" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration\n\nOnly available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`.\nThe MCP server is provided by an ACP component and communicates over the ACP channel.", + "properties": { + "type": { + "const": "acp", + "type": "string" + } + }, + "required": ["type"], + "type": "object" + }, { "allOf": [ { @@ -3363,6 +3618,34 @@ ], "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)" }, + "McpServerAcp": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration for MCP.\n\nThe MCP server is provided by an ACP component and communicates over the ACP channel\nusing `mcp/connect`, `mcp/message`, and `mcp/disconnect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "id": { + "allOf": [ + { + "$ref": "#/$defs/McpServerAcpId" + } + ], + "description": "Unique identifier for this MCP server, generated by the component providing it.\n\nProviders MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible\non the same ACP connection." + }, + "name": { + "description": "Human-readable name identifying this MCP server.", + "type": "string" + } + }, + "required": ["name", "id"], + "type": "object" + }, + "McpServerAcpId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nUnique identifier for an MCP server using the ACP transport.\n\nThe value is opaque and generated by the ACP component providing the MCP server. It is\nused by `mcp/connect` to route connection requests back to the component that declared the\nserver.", + "type": "string" + }, "McpServerHttp": { "description": "HTTP transport configuration for MCP.", "properties": { @@ -3451,6 +3734,73 @@ "required": ["name", "command", "args", "env"], "type": "object" }, + "MessageMcpNotification": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nNotification parameters for `mcp/message`.\n\nThis is used when the wrapped MCP message is a notification and the outer JSON-RPC\nenvelope has no `id`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The MCP-over-ACP connection this message is sent on." + }, + "method": { + "description": "The inner MCP method name.", + "type": "string" + }, + "params": { + "additionalProperties": true, + "description": "Optional inner MCP params.\n\nIf omitted or set to `null`, the inner MCP message has no params.", + "type": ["object", "null"] + } + }, + "required": ["connectionId", "method"], + "type": "object", + "x-method": "mcp/message", + "x-side": "both" + }, + "MessageMcpRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `mcp/message`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The MCP-over-ACP connection this message is sent on." + }, + "method": { + "description": "The inner MCP method name.", + "type": "string" + }, + "params": { + "additionalProperties": true, + "description": "Optional inner MCP params.\n\nIf omitted or set to `null`, the inner MCP message has no params.", + "type": ["object", "null"] + } + }, + "required": ["connectionId", "method"], + "type": "object", + "x-method": "mcp/message", + "x-side": "both" + }, + "MessageMcpResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `mcp/message`.\n\nThis is the inner MCP response result payload. Any JSON value is valid.", + "x-method": "mcp/message", + "x-side": "both" + }, "ModelId": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for a model.", "type": "string" @@ -4762,6 +5112,11 @@ "default": false, "description": "Agent supports [`ContentBlock::Image`].", "type": "boolean" + }, + "promptVariables": { + "default": false, + "description": "Agent supports prompt variables and templates in `session/prompt` requests.\n\nWhen enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`]\nin prompt requests with variable substitution support.", + "type": "boolean" } }, "type": "object" @@ -4836,6 +5191,143 @@ "x-method": "session/prompt", "x-side": "agent" }, + "PromptTemplateContent": { + "description": "A template content block that supports variable substitution.\n\nTemplates use {{variable_name}} syntax for variable placeholders that can be\nsubstituted with actual values at processing time. This enables dynamic content\ngeneration and reusable prompt templates.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "annotations": { + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ] + }, + "template": { + "description": "The template string with {{variable_name}} placeholders.", + "type": "string" + }, + "variables": { + "description": "Variables available for substitution in this template.", + "items": { + "$ref": "#/$defs/PromptVariable" + }, + "type": "array" + } + }, + "required": ["template", "variables"], + "type": "object" + }, + "PromptVariable": { + "description": "A variable that can be substituted in a prompt template.\n\nVariables define named placeholders that can be replaced with actual values\nduring template processing. They can include metadata about expected types,\ndescriptions for user interfaces, and validation constraints.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "default_value": { + "description": "Default value to use if no value is provided.", + "type": ["string", "null"] + }, + "description": { + "description": "Human-readable description of this variable.", + "type": ["string", "null"] + }, + "name": { + "description": "The variable name (used in {{variable_name}} placeholders).", + "type": "string" + }, + "required": { + "default": false, + "description": "Whether this variable is required for template processing.", + "type": "boolean" + }, + "type": { + "anyOf": [ + { + "$ref": "#/$defs/PromptVariableType" + }, + { + "type": "null" + } + ], + "description": "The expected type of this variable's value." + }, + "value": { + "description": "The current value of the variable (if set).", + "type": ["string", "null"] + } + }, + "required": ["name"], + "type": "object" + }, + "PromptVariableType": { + "description": "The expected type of a prompt variable's value.\n\nThis helps clients provide appropriate input interfaces and validation\nfor prompt variables.", + "oneOf": [ + { + "const": "string", + "description": "A string value (default if not specified).", + "type": "string" + }, + { + "const": "number", + "description": "A numeric value (integer or float).", + "type": "string" + }, + { + "const": "boolean", + "description": "A boolean value (true/false).", + "type": "string" + }, + { + "const": "date_time", + "description": "A date/time value in ISO 8601 format.", + "type": "string" + }, + { + "const": "url", + "description": "A URL or URI reference.", + "type": "string" + }, + { + "const": "email", + "description": "An email address.", + "type": "string" + }, + { + "const": "text", + "description": "A multiline text value.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "A value selected from a predefined list (enum-like).", + "properties": { + "select": { + "properties": { + "options": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["options"], + "type": "object" + } + }, + "required": ["select"], + "type": "object" + } + ] + }, "ProtocolVersion": { "description": "Protocol version identifier.\n\nThis version is only bumped for breaking changes.\nNon-breaking changes should be introduced via capabilities.", "format": "uint16", @@ -5227,7 +5719,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`.", "items": { "type": "string" }, @@ -5326,7 +5818,7 @@ "type": "object" }, "SessionAdditionalDirectoriesCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsupported session lifecycle requests and `session/list`.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories`\nfield on supported session lifecycle requests. Agents that also support\n`session/list` may return `SessionInfo.additionalDirectories` to report the\ncomplete ordered additional-root list associated with a listed session.", "properties": { "_meta": { "additionalProperties": true, @@ -5353,7 +5845,7 @@ "type": "null" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`." + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on supported session lifecycle requests.\n\nAgents that also support `session/list` may return\n`SessionInfo.additionalDirectories` to report the complete ordered\nadditional-root list associated with a listed session." }, "close": { "anyOf": [ @@ -5366,6 +5858,17 @@ ], "description": "Whether the agent supports `session/close`." }, + "delete": { + "anyOf": [ + { + "$ref": "#/$defs/SessionDeleteCapabilities" + }, + { + "type": "null" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/delete`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports deleting sessions from `session/list`." + }, "fork": { "anyOf": [ { @@ -5640,6 +6143,17 @@ "description": "Unique identifier for a session configuration option value.", "type": "string" }, + "SessionDeleteCapabilities": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for the `session/delete` method.\n\nSupplying `{}` means the agent supports deleting sessions from `session/list`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object" + }, "SessionForkCapabilities": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for the `session/fork` method.\n\nBy supplying `{}` it means that the agent supports forking of sessions.", "properties": { @@ -5664,7 +6178,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthoritative ordered additional workspace roots for this session. Each path must be absolute.\n\nWhen omitted or empty, there are no additional roots for the session.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots reported for this session. Each path must be absolute.\n\nWhen present, this is the complete ordered additional-root list reported\nby the Agent. Omitted and empty values are equivalent: the response\nreports no additional roots.", "items": { "type": "string" }, @@ -6028,7 +6542,7 @@ } ] }, - "SetProvidersRequest": { + "SetProviderRequest": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/set`.\n\nReplaces the full configuration for one provider id.", "properties": { "_meta": { @@ -6065,7 +6579,7 @@ "x-method": "providers/set", "x-side": "agent" }, - "SetProvidersResponse": { + "SetProviderResponse": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/set`.", "properties": { "_meta": { diff --git a/schema/schema.v2.unstable.json b/schema/schema.v2.unstable.json index b304602c4..48a14e5cb 100644 --- a/schema/schema.v2.unstable.json +++ b/schema/schema.v2.unstable.json @@ -27,7 +27,7 @@ "x-side": "agent" }, "AgentAuthCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication-related capabilities supported by the agent.", + "description": "Authentication-related capabilities supported by the agent.", "properties": { "_meta": { "additionalProperties": true, @@ -63,7 +63,7 @@ } ], "default": {}, - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthentication-related capabilities supported by the agent." + "description": "Authentication-related capabilities supported by the agent." }, "loadSession": { "default": false, @@ -77,6 +77,7 @@ } ], "default": { + "acp": false, "http": false, "sse": false }, @@ -113,7 +114,8 @@ "default": { "audio": false, "embeddedContext": false, - "image": false + "image": false, + "promptVariables": false }, "description": "Prompt capabilities supported by the agent." }, @@ -166,6 +168,15 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nNotification that a URL-based elicitation has completed.", "title": "CompleteElicitationNotification" }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpNotification" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nReceives an MCP-over-ACP notification.", + "title": "MessageMcpNotification" + }, { "allOf": [ { @@ -281,6 +292,33 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequests structured user input via a form or URL.", "title": "CreateElicitationRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/ConnectMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nOpens an MCP-over-ACP connection.", + "title": "ConnectMcpRequest" + }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nExchanges an MCP-over-ACP message.", + "title": "MessageMcpRequest" + }, + { + "allOf": [ + { + "$ref": "#/$defs/DisconnectMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCloses an MCP-over-ACP connection.", + "title": "DisconnectMcpRequest" + }, { "allOf": [ { @@ -339,18 +377,18 @@ { "allOf": [ { - "$ref": "#/$defs/SetProvidersResponse" + "$ref": "#/$defs/SetProviderResponse" } ], - "title": "SetProvidersResponse" + "title": "SetProviderResponse" }, { "allOf": [ { - "$ref": "#/$defs/DisableProvidersResponse" + "$ref": "#/$defs/DisableProviderResponse" } ], - "title": "DisableProvidersResponse" + "title": "DisableProviderResponse" }, { "allOf": [ @@ -384,6 +422,14 @@ ], "title": "ListSessionsResponse" }, + { + "allOf": [ + { + "$ref": "#/$defs/DeleteSessionResponse" + } + ], + "title": "DeleteSessionResponse" + }, { "allOf": [ { @@ -471,6 +517,14 @@ } ], "title": "ExtMethodResponse" + }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpResponse" + } + ], + "title": "MessageMcpResponse" } ], "description": "All possible responses that an agent can send to a client.\n\nThis enum is used internally for routing RPC responses. You typically won't need\nto use this directly - the responses are handled automatically by the connection.\n\nThese are responses to the corresponding `ClientRequest` variants." @@ -1108,6 +1162,15 @@ "description": "**UNSTABLE**\n\nNotification sent when a suggestion is rejected.", "title": "RejectNesNotification" }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpNotification" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nSends an MCP-over-ACP notification.", + "title": "MessageMcpNotification" + }, { "allOf": [ { @@ -1172,20 +1235,20 @@ { "allOf": [ { - "$ref": "#/$defs/SetProvidersRequest" + "$ref": "#/$defs/SetProviderRequest" } ], "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nReplaces the configuration for a provider.", - "title": "SetProvidersRequest" + "title": "SetProviderRequest" }, { "allOf": [ { - "$ref": "#/$defs/DisableProvidersRequest" + "$ref": "#/$defs/DisableProviderRequest" } ], "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDisables a provider.", - "title": "DisableProvidersRequest" + "title": "DisableProviderRequest" }, { "allOf": [ @@ -1193,7 +1256,7 @@ "$ref": "#/$defs/LogoutRequest" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLogs out of the current authenticated state.\n\nAfter a successful logout, all new sessions will require authentication.\nThere is no guarantee about the behavior of already running sessions.", + "description": "Logs out of the current authenticated state.\n\nAfter a successful logout, all new sessions will require authentication.\nThere is no guarantee about the behavior of already running sessions.", "title": "LogoutRequest" }, { @@ -1223,6 +1286,15 @@ "description": "Lists existing sessions known to the agent.\n\nThis method is only available if the agent advertises the `sessionCapabilities.list` capability.\n\nThe agent should return metadata about sessions with optional filtering and pagination support.", "title": "ListSessionsRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/DeleteSessionRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nDeletes an existing session from `session/list`.\n\nThis method is only available if the agent advertises the `sessionCapabilities.delete` capability.", + "title": "DeleteSessionRequest" + }, { "allOf": [ { @@ -1313,6 +1385,15 @@ "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCloses an active NES session and frees up any resources associated with it.\n\nThe agent must cancel any ongoing work and then free up any resources\nassociated with the NES session.", "title": "CloseNesRequest" }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpRequest" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nExchanges an MCP-over-ACP message.", + "title": "MessageMcpRequest" + }, { "allOf": [ { @@ -1416,6 +1497,22 @@ ], "title": "CreateElicitationResponse" }, + { + "allOf": [ + { + "$ref": "#/$defs/ConnectMcpResponse" + } + ], + "title": "ConnectMcpResponse" + }, + { + "allOf": [ + { + "$ref": "#/$defs/DisconnectMcpResponse" + } + ], + "title": "DisconnectMcpResponse" + }, { "allOf": [ { @@ -1423,6 +1520,14 @@ } ], "title": "ExtMethodResponse" + }, + { + "allOf": [ + { + "$ref": "#/$defs/MessageMcpResponse" + } + ], + "title": "MessageMcpResponse" } ], "description": "All possible responses that a client can send to an agent.\n\nThis enum is used internally for routing RPC responses. You typically won't need\nto use this directly - the responses are handled automatically by the connection.\n\nThese are responses to the corresponding `AgentRequest` variants." @@ -1559,6 +1664,50 @@ "required": ["configOptions"], "type": "object" }, + "ConnectMcpRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `mcp/connect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "acpId": { + "allOf": [ + { + "$ref": "#/$defs/McpServerAcpId" + } + ], + "description": "The ACP MCP server ID that was provided by the component declaring the MCP server." + } + }, + "required": ["acpId"], + "type": "object", + "x-method": "mcp/connect", + "x-side": "client" + }, + "ConnectMcpResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `mcp/connect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The unique identifier for this MCP-over-ACP connection." + } + }, + "required": ["connectionId"], + "type": "object", + "x-method": "mcp/connect", + "x-side": "client" + }, "Content": { "description": "Standard content block (text, images, resources).", "properties": { @@ -1664,6 +1813,22 @@ }, "required": ["type"], "type": "object" + }, + { + "allOf": [ + { + "$ref": "#/$defs/PromptTemplateContent" + } + ], + "description": "A template that supports variable substitution using {{variable_name}} syntax.\n\nAllows dynamic content generation by substituting variables into template strings.\nVariables are resolved at processing time and can include values from context,\nuser input, or system state.\n\nRequires the `promptVariables` prompt capability when included in prompts.", + "properties": { + "type": { + "const": "prompt_template", + "type": "string" + } + }, + "required": ["type"], + "type": "object" } ] }, @@ -1906,6 +2071,41 @@ "required": ["currentModeId"], "type": "object" }, + "DeleteSessionRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for deleting an existing session from `session/list`.\n\nOnly available if the Agent supports the `sessionCapabilities.delete` capability.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "sessionId": { + "allOf": [ + { + "$ref": "#/$defs/SessionId" + } + ], + "description": "The ID of the session to delete." + } + }, + "required": ["sessionId"], + "type": "object", + "x-method": "session/delete", + "x-side": "agent" + }, + "DeleteSessionResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse from deleting a session.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object", + "x-method": "session/delete", + "x-side": "agent" + }, "DidChangeDocumentNotification": { "description": "Notification sent when a file is edited.", "properties": { @@ -2106,7 +2306,7 @@ "required": ["path", "newText"], "type": "object" }, - "DisableProvidersRequest": { + "DisableProviderRequest": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/disable`.", "properties": { "_meta": { @@ -2124,7 +2324,7 @@ "x-method": "providers/disable", "x-side": "agent" }, - "DisableProvidersResponse": { + "DisableProviderResponse": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/disable`.", "properties": { "_meta": { @@ -2137,6 +2337,41 @@ "x-method": "providers/disable", "x-side": "agent" }, + "DisconnectMcpRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `mcp/disconnect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The MCP-over-ACP connection to close." + } + }, + "required": ["connectionId"], + "type": "object", + "x-method": "mcp/disconnect", + "x-side": "client" + }, + "DisconnectMcpResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `mcp/disconnect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object", + "x-method": "mcp/disconnect", + "x-side": "client" + }, "ElicitationAcceptAction": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nThe user accepted the elicitation and provided content.", "properties": { @@ -2942,13 +3177,15 @@ "auth": {}, "loadSession": false, "mcpCapabilities": { + "acp": false, "http": false, "sse": false }, "promptCapabilities": { "audio": false, "embeddedContext": false, - "image": false + "image": false, + "promptVariables": false }, "sessionCapabilities": {} }, @@ -3097,13 +3334,6 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, - "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nFilter sessions by the exact ordered additional workspace roots. Each path must be absolute.\n\nThis filter applies only when the field is present and non-empty. When\nomitted or empty, no additional-root filter is applied.", - "items": { - "type": "string" - }, - "type": "array" - }, "cursor": { "description": "Opaque cursor token from a previous response's nextCursor field for cursor-based pagination", "type": ["string", "null"] @@ -3186,7 +3416,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the loaded\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`.", "items": { "type": "string" }, @@ -3260,7 +3490,7 @@ "x-side": "agent" }, "LogoutCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nLogout capabilities supported by the agent.\n\nBy supplying `{}` it means that the agent supports the logout method.", + "description": "Logout capabilities supported by the agent.\n\nBy supplying `{}` it means that the agent supports the logout method.", "properties": { "_meta": { "additionalProperties": true, @@ -3271,7 +3501,7 @@ "type": "object" }, "LogoutRequest": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for the logout method.\n\nTerminates the current authenticated session.", + "description": "Request parameters for the logout method.\n\nTerminates the current authenticated session.", "properties": { "_meta": { "additionalProperties": true, @@ -3284,7 +3514,7 @@ "x-side": "agent" }, "LogoutResponse": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to the `logout` method.", + "description": "Response to the `logout` method.", "properties": { "_meta": { "additionalProperties": true, @@ -3304,6 +3534,11 @@ "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", "type": ["object", "null"] }, + "acp": { + "default": false, + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAgent supports [`McpServer::Acp`].", + "type": "boolean" + }, "http": { "default": false, "description": "Agent supports [`McpServer::Http`].", @@ -3317,6 +3552,10 @@ }, "type": "object" }, + "McpConnectionId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for an active MCP-over-ACP connection.", + "type": "string" + }, "McpServer": { "anyOf": [ { @@ -3351,6 +3590,22 @@ "required": ["type"], "type": "object" }, + { + "allOf": [ + { + "$ref": "#/$defs/McpServerAcp" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration\n\nOnly available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`.\nThe MCP server is provided by an ACP component and communicates over the ACP channel.", + "properties": { + "type": { + "const": "acp", + "type": "string" + } + }, + "required": ["type"], + "type": "object" + }, { "allOf": [ { @@ -3363,6 +3618,34 @@ ], "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)" }, + "McpServerAcp": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration for MCP.\n\nThe MCP server is provided by an ACP component and communicates over the ACP channel\nusing `mcp/connect`, `mcp/message`, and `mcp/disconnect`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "id": { + "allOf": [ + { + "$ref": "#/$defs/McpServerAcpId" + } + ], + "description": "Unique identifier for this MCP server, generated by the component providing it.\n\nProviders MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible\non the same ACP connection." + }, + "name": { + "description": "Human-readable name identifying this MCP server.", + "type": "string" + } + }, + "required": ["name", "id"], + "type": "object" + }, + "McpServerAcpId": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nUnique identifier for an MCP server using the ACP transport.\n\nThe value is opaque and generated by the ACP component providing the MCP server. It is\nused by `mcp/connect` to route connection requests back to the component that declared the\nserver.", + "type": "string" + }, "McpServerHttp": { "description": "HTTP transport configuration for MCP.", "properties": { @@ -3451,6 +3734,73 @@ "required": ["name", "command", "args", "env"], "type": "object" }, + "MessageMcpNotification": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nNotification parameters for `mcp/message`.\n\nThis is used when the wrapped MCP message is a notification and the outer JSON-RPC\nenvelope has no `id`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The MCP-over-ACP connection this message is sent on." + }, + "method": { + "description": "The inner MCP method name.", + "type": "string" + }, + "params": { + "additionalProperties": true, + "description": "Optional inner MCP params.\n\nIf omitted or set to `null`, the inner MCP message has no params.", + "type": ["object", "null"] + } + }, + "required": ["connectionId", "method"], + "type": "object", + "x-method": "mcp/message", + "x-side": "both" + }, + "MessageMcpRequest": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `mcp/message`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "connectionId": { + "allOf": [ + { + "$ref": "#/$defs/McpConnectionId" + } + ], + "description": "The MCP-over-ACP connection this message is sent on." + }, + "method": { + "description": "The inner MCP method name.", + "type": "string" + }, + "params": { + "additionalProperties": true, + "description": "Optional inner MCP params.\n\nIf omitted or set to `null`, the inner MCP message has no params.", + "type": ["object", "null"] + } + }, + "required": ["connectionId", "method"], + "type": "object", + "x-method": "mcp/message", + "x-side": "both" + }, + "MessageMcpResponse": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `mcp/message`.\n\nThis is the inner MCP response result payload. Any JSON value is valid.", + "x-method": "mcp/message", + "x-side": "both" + }, "ModelId": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nA unique identifier for a model.", "type": "string" @@ -4762,6 +5112,11 @@ "default": false, "description": "Agent supports [`ContentBlock::Image`].", "type": "boolean" + }, + "promptVariables": { + "default": false, + "description": "Agent supports prompt variables and templates in `session/prompt` requests.\n\nWhen enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`]\nin prompt requests with variable substitution support.", + "type": "boolean" } }, "type": "object" @@ -4836,6 +5191,143 @@ "x-method": "session/prompt", "x-side": "agent" }, + "PromptTemplateContent": { + "description": "A template content block that supports variable substitution.\n\nTemplates use {{variable_name}} syntax for variable placeholders that can be\nsubstituted with actual values at processing time. This enables dynamic content\ngeneration and reusable prompt templates.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "annotations": { + "anyOf": [ + { + "$ref": "#/$defs/Annotations" + }, + { + "type": "null" + } + ] + }, + "template": { + "description": "The template string with {{variable_name}} placeholders.", + "type": "string" + }, + "variables": { + "description": "Variables available for substitution in this template.", + "items": { + "$ref": "#/$defs/PromptVariable" + }, + "type": "array" + } + }, + "required": ["template", "variables"], + "type": "object" + }, + "PromptVariable": { + "description": "A variable that can be substituted in a prompt template.\n\nVariables define named placeholders that can be replaced with actual values\nduring template processing. They can include metadata about expected types,\ndescriptions for user interfaces, and validation constraints.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + }, + "default_value": { + "description": "Default value to use if no value is provided.", + "type": ["string", "null"] + }, + "description": { + "description": "Human-readable description of this variable.", + "type": ["string", "null"] + }, + "name": { + "description": "The variable name (used in {{variable_name}} placeholders).", + "type": "string" + }, + "required": { + "default": false, + "description": "Whether this variable is required for template processing.", + "type": "boolean" + }, + "type": { + "anyOf": [ + { + "$ref": "#/$defs/PromptVariableType" + }, + { + "type": "null" + } + ], + "description": "The expected type of this variable's value." + }, + "value": { + "description": "The current value of the variable (if set).", + "type": ["string", "null"] + } + }, + "required": ["name"], + "type": "object" + }, + "PromptVariableType": { + "description": "The expected type of a prompt variable's value.\n\nThis helps clients provide appropriate input interfaces and validation\nfor prompt variables.", + "oneOf": [ + { + "const": "string", + "description": "A string value (default if not specified).", + "type": "string" + }, + { + "const": "number", + "description": "A numeric value (integer or float).", + "type": "string" + }, + { + "const": "boolean", + "description": "A boolean value (true/false).", + "type": "string" + }, + { + "const": "date_time", + "description": "A date/time value in ISO 8601 format.", + "type": "string" + }, + { + "const": "url", + "description": "A URL or URI reference.", + "type": "string" + }, + { + "const": "email", + "description": "An email address.", + "type": "string" + }, + { + "const": "text", + "description": "A multiline text value.", + "type": "string" + }, + { + "additionalProperties": false, + "description": "A value selected from a predefined list (enum-like).", + "properties": { + "select": { + "properties": { + "options": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": ["options"], + "type": "object" + } + }, + "required": ["select"], + "type": "object" + } + ] + }, "ProtocolVersion": { "description": "Protocol version identifier.\n\nThis version is only bumped for breaking changes.\nNon-breaking changes should be introduced via capabilities.", "format": "uint16", @@ -5227,7 +5719,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots to activate for this session. Each path must be absolute.\n\nWhen omitted or empty, no additional roots are activated. When non-empty,\nthis is the complete resulting additional-root list for the resumed\nsession. It may differ from any previously used or reported list as long as\nthe request `cwd` matches the session's `cwd`.", "items": { "type": "string" }, @@ -5326,7 +5818,7 @@ "type": "object" }, "SessionAdditionalDirectoriesCapabilities": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories` field on\nsupported session lifecycle requests and `session/list`.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for additional session directories support.\n\nBy supplying `{}` it means that the agent supports the `additionalDirectories`\nfield on supported session lifecycle requests. Agents that also support\n`session/list` may return `SessionInfo.additionalDirectories` to report the\ncomplete ordered additional-root list associated with a listed session.", "properties": { "_meta": { "additionalProperties": true, @@ -5353,7 +5845,7 @@ "type": "null" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`." + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `additionalDirectories` on supported session lifecycle requests.\n\nAgents that also support `session/list` may return\n`SessionInfo.additionalDirectories` to report the complete ordered\nadditional-root list associated with a listed session." }, "close": { "anyOf": [ @@ -5366,6 +5858,17 @@ ], "description": "Whether the agent supports `session/close`." }, + "delete": { + "anyOf": [ + { + "$ref": "#/$defs/SessionDeleteCapabilities" + }, + { + "type": "null" + } + ], + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nWhether the agent supports `session/delete`.\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports deleting sessions from `session/list`." + }, "fork": { "anyOf": [ { @@ -5640,6 +6143,17 @@ "description": "Unique identifier for a session configuration option value.", "type": "string" }, + "SessionDeleteCapabilities": { + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for the `session/delete` method.\n\nSupplying `{}` means the agent supports deleting sessions from `session/list`.", + "properties": { + "_meta": { + "additionalProperties": true, + "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", + "type": ["object", "null"] + } + }, + "type": "object" + }, "SessionForkCapabilities": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nCapabilities for the `session/fork` method.\n\nBy supplying `{}` it means that the agent supports forking of sessions.", "properties": { @@ -5664,7 +6178,7 @@ "type": ["object", "null"] }, "additionalDirectories": { - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAuthoritative ordered additional workspace roots for this session. Each path must be absolute.\n\nWhen omitted or empty, there are no additional roots for the session.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nAdditional workspace roots reported for this session. Each path must be absolute.\n\nWhen present, this is the complete ordered additional-root list reported\nby the Agent. Omitted and empty values are equivalent: the response\nreports no additional roots.", "items": { "type": "string" }, @@ -6028,7 +6542,7 @@ } ] }, - "SetProvidersRequest": { + "SetProviderRequest": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nRequest parameters for `providers/set`.\n\nReplaces the full configuration for one provider id.", "properties": { "_meta": { @@ -6065,7 +6579,7 @@ "x-method": "providers/set", "x-side": "agent" }, - "SetProvidersResponse": { + "SetProviderResponse": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nResponse to `providers/set`.", "properties": { "_meta": { diff --git a/src/bin/generate.rs b/src/bin/generate.rs index 4d96cf611..a68085f4b 100644 --- a/src/bin/generate.rs +++ b/src/bin/generate.rs @@ -171,7 +171,7 @@ fn main() { mod markdown_generator { use serde_json::Value; - use std::collections::{BTreeMap, HashMap}; + use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::fmt::Write; use std::fs; use std::process::Command; @@ -189,6 +189,7 @@ mod markdown_generator { } } + #[expect(clippy::too_many_lines)] pub fn generate(&mut self, schema: &Value) -> String { // Extract definitions if let Some(defs) = schema.get("$defs").and_then(|v| v.as_object()) { @@ -205,6 +206,12 @@ mod markdown_generator { .unwrap(); writeln!(&mut self.output, "---").unwrap(); writeln!(&mut self.output).unwrap(); + writeln!( + &mut self.output, + "The schema file can be downloaded directly from the [latest GitHub release](https://github.com/agentclientprotocol/agent-client-protocol/releases/latest/download/schema.json)." + ) + .unwrap(); + writeln!(&mut self.output).unwrap(); let mut agent_types: BTreeMap> = BTreeMap::new(); let mut client_types: BTreeMap> = BTreeMap::new(); @@ -227,6 +234,18 @@ mod markdown_generator { "agent" => &mut agent_types, "client" => &mut client_types, "protocol" => &mut protocol_types, + "both" => { + let entry = (name.clone(), def.clone()); + agent_types + .entry(method.to_string()) + .or_default() + .push(entry.clone()); + client_types + .entry(method.to_string()) + .or_default() + .push(entry); + continue; + } _ => unimplemented!("Unexpected side {side}"), }; @@ -240,6 +259,17 @@ mod markdown_generator { } let side_docs = extract_side_docs(); + let mut duplicate_methods = BTreeSet::new(); + for method in agent_types.keys() { + if client_types.contains_key(method) || protocol_types.contains_key(method) { + duplicate_methods.insert(method.clone()); + } + } + for method in client_types.keys() { + if protocol_types.contains_key(method) { + duplicate_methods.insert(method.clone()); + } + } writeln!(&mut self.output, "## Agent").unwrap(); writeln!(&mut self.output).unwrap(); @@ -254,7 +284,13 @@ requests from clients and execute tasks using language models and tools." writeln!(&mut self.output).unwrap(); for (method, types) in agent_types { - self.generate_method(&method, side_docs.agent_method_doc(&method), types); + let anchor_prefix = duplicate_methods.contains(&method).then_some("agent"); + self.generate_method( + anchor_prefix, + &method, + side_docs.agent_method_doc(&method), + types, + ); } writeln!(&mut self.output, "## Client").unwrap(); @@ -270,7 +306,13 @@ and control access to resources." .unwrap(); for (method, types) in client_types { - self.generate_method(&method, side_docs.client_method_doc(&method), types); + let anchor_prefix = duplicate_methods.contains(&method).then_some("client"); + self.generate_method( + anchor_prefix, + &method, + side_docs.client_method_doc(&method), + types, + ); } #[cfg(feature = "unstable_cancel_request")] { @@ -290,7 +332,13 @@ starting with '$/' it is free to ignore the notification." .unwrap(); for (method, types) in protocol_types { - self.generate_method(&method, side_docs.protocol_method_doc(&method), types); + let anchor_prefix = duplicate_methods.contains(&method).then_some("protocol"); + self.generate_method( + anchor_prefix, + &method, + side_docs.protocol_method_doc(&method), + types, + ); } } @@ -304,17 +352,17 @@ starting with '$/' it is free to ignore the notification." fn generate_method( &mut self, + anchor_prefix: Option<&str>, method: &str, docs: &str, mut method_types: Vec<(String, Value)>, ) { if method.contains('/') { - writeln!( - &mut self.output, - "", - Self::anchor_text(method).replace('/', "-") - ) - .unwrap(); + let mut anchor = Self::anchor_text(method).replace('/', "-"); + if let Some(prefix) = anchor_prefix { + anchor = format!("{prefix}-{anchor}"); + } + writeln!(&mut self.output, "").unwrap(); } writeln!( &mut self.output, @@ -1122,11 +1170,12 @@ starting with '$/' it is free to ignore the notification." "initialize" => self.agent.get("InitializeRequest").unwrap(), "authenticate" => self.agent.get("AuthenticateRequest").unwrap(), "providers/list" => self.agent.get("ListProvidersRequest").unwrap(), - "providers/set" => self.agent.get("SetProvidersRequest").unwrap(), - "providers/disable" => self.agent.get("DisableProvidersRequest").unwrap(), + "providers/set" => self.agent.get("SetProviderRequest").unwrap(), + "providers/disable" => self.agent.get("DisableProviderRequest").unwrap(), "session/new" => self.agent.get("NewSessionRequest").unwrap(), "session/load" => self.agent.get("LoadSessionRequest").unwrap(), "session/list" => self.agent.get("ListSessionsRequest").unwrap(), + "session/delete" => self.agent.get("DeleteSessionRequest").unwrap(), "session/fork" => self.agent.get("ForkSessionRequest").unwrap(), "session/resume" => self.agent.get("ResumeSessionRequest").unwrap(), "session/set_mode" => self.agent.get("SetSessionModeRequest").unwrap(), @@ -1148,6 +1197,7 @@ starting with '$/' it is free to ignore the notification." "document/didClose" => self.agent.get("DidCloseDocumentNotification").unwrap(), "document/didSave" => self.agent.get("DidSaveDocumentNotification").unwrap(), "document/didFocus" => self.agent.get("DidFocusDocumentNotification").unwrap(), + "mcp/message" => self.agent.get("MessageMcpRequest").unwrap(), _ => panic!("Introduced a method? Add it here :)"), } } @@ -1169,6 +1219,9 @@ starting with '$/' it is free to ignore the notification." "elicitation/complete" => { self.client.get("CompleteElicitationNotification").unwrap() } + "mcp/connect" => self.client.get("ConnectMcpRequest").unwrap(), + "mcp/message" => self.client.get("MessageMcpRequest").unwrap(), + "mcp/disconnect" => self.client.get("DisconnectMcpRequest").unwrap(), _ => panic!("Introduced a method? Add it here :)"), } } diff --git a/src/v1/agent.rs b/src/v1/agent.rs index 004988887..d31fd3265 100644 --- a/src/v1/agent.rs +++ b/src/v1/agent.rs @@ -18,6 +18,11 @@ use crate::{ ProtocolVersion, SessionId, SkipListener, }; +#[cfg(feature = "unstable_mcp_over_acp")] +use super::mcp::{ + MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse, +}; + #[cfg(feature = "unstable_nes")] use crate::{ AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification, @@ -330,14 +335,9 @@ impl AuthenticateResponse { // Logout -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Request parameters for the logout method. /// /// Terminates the current authenticated session. -#[cfg(feature = "unstable_logout")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))] @@ -353,7 +353,6 @@ pub struct LogoutRequest { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl LogoutRequest { #[must_use] pub fn new() -> Self { @@ -372,12 +371,7 @@ impl LogoutRequest { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Response to the `logout` method. -#[cfg(feature = "unstable_logout")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))] @@ -393,7 +387,6 @@ pub struct LogoutResponse { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl LogoutResponse { #[must_use] pub fn new() -> Self { @@ -412,12 +405,7 @@ impl LogoutResponse { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Authentication-related capabilities supported by the agent. -#[cfg(feature = "unstable_logout")] #[serde_as] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -439,7 +427,6 @@ pub struct AgentAuthCapabilities { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl AgentAuthCapabilities { #[must_use] pub fn new() -> Self { @@ -465,14 +452,9 @@ impl AgentAuthCapabilities { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Logout capabilities supported by the agent. /// /// By supplying `{}` it means that the agent supports the logout method. -#[cfg(feature = "unstable_logout")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive] @@ -486,7 +468,6 @@ pub struct LogoutCapabilities { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl LogoutCapabilities { #[must_use] pub fn new() -> Self { @@ -1115,7 +1096,8 @@ pub struct LoadSessionRequest { /// /// When omitted or empty, no additional roots are activated. When non-empty, /// this is the complete resulting additional-root list for the loaded - /// session. + /// session. It may differ from any previously used or reported list as long as + /// the request `cwd` matches the session's `cwd`. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1477,7 +1459,8 @@ pub struct ResumeSessionRequest { /// /// When omitted or empty, no additional roots are activated. When non-empty, /// this is the complete resulting additional-root list for the resumed - /// session. + /// session. It may differ from any previously used or reported list as long as + /// the request `cwd` matches the session's `cwd`. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1716,17 +1699,6 @@ impl CloseSessionResponse { pub struct ListSessionsRequest { /// Filter sessions by working directory. Must be an absolute path. pub cwd: Option, - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// - /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - /// - /// This filter applies only when the field is present and non-empty. When - /// omitted or empty, no additional-root filter is applied. - #[cfg(feature = "unstable_session_additional_directories")] - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub additional_directories: Vec, /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination pub cursor: Option, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -1751,18 +1723,6 @@ impl ListSessionsRequest { self } - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// - /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - #[cfg(feature = "unstable_session_additional_directories")] - #[must_use] - pub fn additional_directories(mut self, additional_directories: Vec) -> Self { - self.additional_directories = additional_directories; - self - } - /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination #[must_use] pub fn cursor(mut self, cursor: impl IntoOption) -> Self { @@ -1833,6 +1793,95 @@ impl ListSessionsResponse { } } +// Delete session + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for deleting an existing session from `session/list`. +/// +/// Only available if the Agent supports the `sessionCapabilities.delete` capability. +#[cfg(feature = "unstable_session_delete")] +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct DeleteSessionRequest { + /// The ID of the session to delete. + pub session_id: SessionId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_session_delete")] +impl DeleteSessionRequest { + #[must_use] + pub fn new(session_id: impl Into) -> Self { + Self { + session_id: session_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response from deleting a session. +#[cfg(feature = "unstable_session_delete")] +#[skip_serializing_none] +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct DeleteSessionResponse { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_session_delete")] +impl DeleteSessionResponse { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + /// Information about a session returned by session/list #[serde_as] #[skip_serializing_none] @@ -1848,9 +1897,11 @@ pub struct SessionInfo { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + /// Additional workspace roots reported for this session. Each path must be absolute. /// - /// When omitted or empty, there are no additional roots for the session. + /// When present, this is the complete ordered additional-root list reported + /// by the Agent. Omitted and empty values are equivalent: the response + /// reports no additional roots. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1890,7 +1941,7 @@ impl SessionInfo { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + /// Additional workspace roots reported for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories(mut self, additional_directories: Vec) -> Self { @@ -2689,6 +2740,16 @@ pub enum McpServer { /// /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`. Sse(McpServerSse), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// ACP transport configuration + /// + /// Only available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`. + /// The MCP server is provided by an ACP component and communicates over the ACP channel. + #[cfg(feature = "unstable_mcp_over_acp")] + Acp(McpServerAcp), /// Stdio transport configuration /// /// All Agents MUST support this transport. @@ -2798,6 +2859,83 @@ impl McpServerSse { } } +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Unique identifier for an MCP server using the ACP transport. +/// +/// The value is opaque and generated by the ACP component providing the MCP server. It is +/// used by `mcp/connect` to route connection requests back to the component that declared the +/// server. +#[cfg(feature = "unstable_mcp_over_acp")] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)] +#[serde(transparent)] +#[from(Arc, String, &'static str)] +#[non_exhaustive] +pub struct McpServerAcpId(pub Arc); + +#[cfg(feature = "unstable_mcp_over_acp")] +impl McpServerAcpId { + #[must_use] + pub fn new(id: impl Into>) -> Self { + Self(id.into()) + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// ACP transport configuration for MCP. +/// +/// The MCP server is provided by an ACP component and communicates over the ACP channel +/// using `mcp/connect`, `mcp/message`, and `mcp/disconnect`. +#[skip_serializing_none] +#[cfg(feature = "unstable_mcp_over_acp")] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct McpServerAcp { + /// Human-readable name identifying this MCP server. + pub name: String, + /// Unique identifier for this MCP server, generated by the component providing it. + /// + /// Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible + /// on the same ACP connection. + pub id: McpServerAcpId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl McpServerAcp { + #[must_use] + pub fn new(name: impl Into, id: impl Into) -> Self { + Self { + name: name.into(), + id: id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + /// Stdio transport configuration for MCP. #[skip_serializing_none] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -3652,7 +3790,7 @@ impl ListProvidersResponse { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProvidersRequest { +pub struct SetProviderRequest { /// Provider id to configure. pub id: String, /// Protocol type for this provider. @@ -3673,7 +3811,7 @@ pub struct SetProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl SetProvidersRequest { +impl SetProviderRequest { #[must_use] pub fn new(id: impl Into, api_type: LlmProtocol, base_url: impl Into) -> Self { Self { @@ -3716,7 +3854,7 @@ impl SetProvidersRequest { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProvidersResponse { +pub struct SetProviderResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3727,7 +3865,7 @@ pub struct SetProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl SetProvidersResponse { +impl SetProviderResponse { #[must_use] pub fn new() -> Self { Self::default() @@ -3756,7 +3894,7 @@ impl SetProvidersResponse { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProvidersRequest { +pub struct DisableProviderRequest { /// Provider id to disable. pub id: String, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3769,7 +3907,7 @@ pub struct DisableProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProvidersRequest { +impl DisableProviderRequest { #[must_use] pub fn new(id: impl Into) -> Self { Self { @@ -3801,7 +3939,7 @@ impl DisableProvidersRequest { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProvidersResponse { +pub struct DisableProviderResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3812,7 +3950,7 @@ pub struct DisableProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProvidersResponse { +impl DisableProviderResponse { #[must_use] pub fn new() -> Self { Self::default() @@ -3855,12 +3993,7 @@ pub struct AgentCapabilities { pub mcp_capabilities: McpCapabilities, #[serde(default)] pub session_capabilities: SessionCapabilities, - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// /// Authentication-related capabilities supported by the agent. - #[cfg(feature = "unstable_logout")] #[serde(default)] pub auth: AgentAuthCapabilities, /// **UNSTABLE** @@ -3935,12 +4068,7 @@ impl AgentCapabilities { self } - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// /// Authentication-related capabilities supported by the agent. - #[cfg(feature = "unstable_logout")] #[must_use] pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self { self.auth = auth; @@ -4059,7 +4187,23 @@ pub struct SessionCapabilities { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. + /// Whether the agent supports `session/delete`. + /// + /// Optional. Omitted or `null` both mean the agent does not advertise support. + /// Supplying `{}` means the agent supports deleting sessions from `session/list`. + #[cfg(feature = "unstable_session_delete")] + #[serde_as(deserialize_as = "DefaultOnError")] + #[serde(default)] + pub delete: Option, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests. + /// + /// Agents that also support `session/list` may return + /// `SessionInfo.additionalDirectories` to report the complete ordered + /// additional-root list associated with a listed session. #[cfg(feature = "unstable_session_additional_directories")] #[serde_as(deserialize_as = "DefaultOnError")] #[serde(default)] @@ -4107,7 +4251,26 @@ impl SessionCapabilities { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. + /// Whether the agent supports `session/delete`. + /// + /// Omitted or `null` both mean the agent does not advertise support. + /// Supplying `{}` means the agent supports deleting sessions from `session/list`. + #[cfg(feature = "unstable_session_delete")] + #[must_use] + pub fn delete(mut self, delete: impl IntoOption) -> Self { + self.delete = delete.into_option(); + self + } + + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests. + /// + /// Agents that also support `session/list` may return + /// `SessionInfo.additionalDirectories` to report the complete ordered + /// additional-root list associated with a listed session. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( @@ -4186,14 +4349,56 @@ impl SessionListCapabilities { } } +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Capabilities for the `session/delete` method. +/// +/// Supplying `{}` means the agent supports deleting sessions from `session/list`. +#[cfg(feature = "unstable_session_delete")] +#[skip_serializing_none] +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[non_exhaustive] +pub struct SessionDeleteCapabilities { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_session_delete")] +impl SessionDeleteCapabilities { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Capabilities for additional session directories support. /// -/// By supplying `{}` it means that the agent supports the `additionalDirectories` field on -/// supported session lifecycle requests and `session/list`. +/// By supplying `{}` it means that the agent supports the `additionalDirectories` +/// field on supported session lifecycle requests. Agents that also support +/// `session/list` may return `SessionInfo.additionalDirectories` to report the +/// complete ordered additional-root list associated with a listed session. #[cfg(feature = "unstable_session_additional_directories")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -4351,6 +4556,7 @@ impl SessionCloseCapabilities { #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "camelCase")] #[non_exhaustive] +#[allow(clippy::struct_excessive_bools)] pub struct PromptCapabilities { /// Agent supports [`ContentBlock::Image`]. #[serde(default)] @@ -4364,6 +4570,12 @@ pub struct PromptCapabilities { /// in prompt requests for pieces of context that are referenced in the message. #[serde(default)] pub embedded_context: bool, + /// Agent supports prompt variables and templates in `session/prompt` requests. + /// + /// When enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`] + /// in prompt requests with variable substitution support. + #[serde(default)] + pub prompt_variables: bool, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4403,6 +4615,16 @@ impl PromptCapabilities { self } + /// Agent supports prompt variables and templates in `session/prompt` requests. + /// + /// When enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`] + /// in prompt requests with variable substitution support. + #[must_use] + pub fn prompt_variables(mut self, prompt_variables: bool) -> Self { + self.prompt_variables = prompt_variables; + self + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4427,6 +4649,14 @@ pub struct McpCapabilities { /// Agent supports [`McpServer::Sse`]. #[serde(default)] pub sse: bool, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Agent supports [`McpServer::Acp`]. + #[cfg(feature = "unstable_mcp_over_acp")] + #[serde(default)] + pub acp: bool, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4456,6 +4686,18 @@ impl McpCapabilities { self } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Agent supports [`McpServer::Acp`]. + #[cfg(feature = "unstable_mcp_over_acp")] + #[must_use] + pub fn acp(mut self, acp: bool) -> Self { + self.acp = acp; + self + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4501,11 +4743,17 @@ pub struct AgentMethodNames { pub session_prompt: &'static str, /// Notification for cancelling operations. pub session_cancel: &'static str, + /// Method for exchanging MCP-over-ACP messages. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_message: &'static str, /// Method for selecting a model for a given session. #[cfg(feature = "unstable_session_model")] pub session_set_model: &'static str, /// Method for listing existing sessions. pub session_list: &'static str, + /// Method for deleting an existing session. + #[cfg(feature = "unstable_session_delete")] + pub session_delete: &'static str, /// Method for forking an existing session. #[cfg(feature = "unstable_session_fork")] pub session_fork: &'static str, @@ -4514,7 +4762,6 @@ pub struct AgentMethodNames { /// Method for closing an active session. pub session_close: &'static str, /// Method for logging out of an authenticated session. - #[cfg(feature = "unstable_logout")] pub logout: &'static str, /// Method for starting an NES session. #[cfg(feature = "unstable_nes")] @@ -4564,14 +4811,17 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME, session_prompt: SESSION_PROMPT_METHOD_NAME, session_cancel: SESSION_CANCEL_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_message: MCP_MESSAGE_METHOD_NAME, #[cfg(feature = "unstable_session_model")] session_set_model: SESSION_SET_MODEL_METHOD_NAME, session_list: SESSION_LIST_METHOD_NAME, + #[cfg(feature = "unstable_session_delete")] + session_delete: SESSION_DELETE_METHOD_NAME, #[cfg(feature = "unstable_session_fork")] session_fork: SESSION_FORK_METHOD_NAME, session_resume: SESSION_RESUME_METHOD_NAME, session_close: SESSION_CLOSE_METHOD_NAME, - #[cfg(feature = "unstable_logout")] logout: LOGOUT_METHOD_NAME, #[cfg(feature = "unstable_nes")] nes_start: NES_START_METHOD_NAME, @@ -4625,6 +4875,9 @@ pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel"; pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model"; /// Method name for listing existing sessions. pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list"; +/// Method name for deleting an existing session. +#[cfg(feature = "unstable_session_delete")] +pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete"; /// Method name for forking an existing session. #[cfg(feature = "unstable_session_fork")] pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork"; @@ -4633,7 +4886,6 @@ pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume"; /// Method name for closing an active session. pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close"; /// Method name for logging out of an authenticated session. -#[cfg(feature = "unstable_logout")] pub(crate) const LOGOUT_METHOD_NAME: &str = "logout"; /// All possible requests that a client can send to an agent. @@ -4682,23 +4934,18 @@ pub enum ClientRequest { /// /// Replaces the configuration for a provider. #[cfg(feature = "unstable_llm_providers")] - SetProvidersRequest(SetProvidersRequest), + SetProviderRequest(SetProviderRequest), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Disables a provider. #[cfg(feature = "unstable_llm_providers")] - DisableProvidersRequest(DisableProvidersRequest), - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// + DisableProviderRequest(DisableProviderRequest), /// Logs out of the current authenticated state. /// /// After a successful logout, all new sessions will require authentication. /// There is no guarantee about the behavior of already running sessions. - #[cfg(feature = "unstable_logout")] LogoutRequest(LogoutRequest), /// Creates a new conversation session with the agent. /// @@ -4730,6 +4977,15 @@ pub enum ClientRequest { /// /// The agent should return metadata about sessions with optional filtering and pagination support. ListSessionsRequest(ListSessionsRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Deletes an existing session from `session/list`. + /// + /// This method is only available if the agent advertises the `sessionCapabilities.delete` capability. + #[cfg(feature = "unstable_session_delete")] + DeleteSessionRequest(DeleteSessionRequest), #[cfg(feature = "unstable_session_fork")] /// **UNSTABLE** /// @@ -4816,6 +5072,13 @@ pub enum ClientRequest { /// The agent must cancel any ongoing work and then free up any resources /// associated with the NES session. CloseNesRequest(CloseNesRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Exchanges an MCP-over-ACP message. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpRequest(MessageMcpRequest), /// Handles extension method requests from the client. /// /// Extension methods provide a way to add custom functionality while maintaining @@ -4835,14 +5098,15 @@ impl ClientRequest { #[cfg(feature = "unstable_llm_providers")] Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list, #[cfg(feature = "unstable_llm_providers")] - Self::SetProvidersRequest(_) => AGENT_METHOD_NAMES.providers_set, + Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set, #[cfg(feature = "unstable_llm_providers")] - Self::DisableProvidersRequest(_) => AGENT_METHOD_NAMES.providers_disable, - #[cfg(feature = "unstable_logout")] + Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable, Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout, Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new, Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load, Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list, + #[cfg(feature = "unstable_session_delete")] + Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete, #[cfg(feature = "unstable_session_fork")] Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork, Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume, @@ -4858,6 +5122,8 @@ impl ClientRequest { Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest, #[cfg(feature = "unstable_nes")] Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message, Self::ExtMethodRequest(ext_request) => &ext_request.method, } } @@ -4880,14 +5146,15 @@ pub enum AgentResponse { #[cfg(feature = "unstable_llm_providers")] ListProvidersResponse(ListProvidersResponse), #[cfg(feature = "unstable_llm_providers")] - SetProvidersResponse(#[serde(default)] SetProvidersResponse), + SetProviderResponse(#[serde(default)] SetProviderResponse), #[cfg(feature = "unstable_llm_providers")] - DisableProvidersResponse(#[serde(default)] DisableProvidersResponse), - #[cfg(feature = "unstable_logout")] + DisableProviderResponse(#[serde(default)] DisableProviderResponse), LogoutResponse(#[serde(default)] LogoutResponse), NewSessionResponse(NewSessionResponse), LoadSessionResponse(#[serde(default)] LoadSessionResponse), ListSessionsResponse(ListSessionsResponse), + #[cfg(feature = "unstable_session_delete")] + DeleteSessionResponse(#[serde(default)] DeleteSessionResponse), #[cfg(feature = "unstable_session_fork")] ForkSessionResponse(ForkSessionResponse), ResumeSessionResponse(#[serde(default)] ResumeSessionResponse), @@ -4904,6 +5171,8 @@ pub enum AgentResponse { #[cfg(feature = "unstable_nes")] CloseNesResponse(#[serde(default)] CloseNesResponse), ExtMethodResponse(ExtResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpResponse(MessageMcpResponse), } /// All possible notifications that a client can send to an agent. @@ -4964,6 +5233,13 @@ pub enum ClientNotification { /// /// Notification sent when a suggestion is rejected. RejectNesNotification(RejectNesNotification), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Sends an MCP-over-ACP notification. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpNotification(MessageMcpNotification), /// Handles extension notifications from the client. /// /// Extension notifications provide a way to send one-way messages for custom functionality @@ -4993,6 +5269,8 @@ impl ClientNotification { Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept, #[cfg(feature = "unstable_nes")] Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message, Self::ExtNotification(ext_notification) => &ext_notification.method, } } @@ -5137,6 +5415,104 @@ mod test_serialization { } } + #[cfg(feature = "unstable_mcp_over_acp")] + #[test] + fn test_mcp_server_acp_serialization() { + let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id")); + + let json = serde_json::to_value(&server).unwrap(); + assert_eq!( + json, + json!({ + "type": "acp", + "name": "project-tools", + "id": "project-tools-id" + }) + ); + + let deserialized: McpServer = serde_json::from_value(json).unwrap(); + match deserialized { + McpServer::Acp(McpServerAcp { name, id, meta: _ }) => { + assert_eq!(name, "project-tools"); + assert_eq!(id, McpServerAcpId::new("project-tools-id")); + } + _ => panic!("Expected Acp variant"), + } + } + + #[cfg(feature = "unstable_mcp_over_acp")] + #[test] + fn test_client_mcp_message_method_names() { + assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message"); + + assert_eq!( + ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list")) + .method(), + "mcp/message" + ); + assert_eq!( + ClientNotification::MessageMcpNotification(MessageMcpNotification::new( + "conn-1", + "notifications/progress" + )) + .method(), + "mcp/message" + ); + } + + #[cfg(feature = "unstable_mcp_over_acp")] + #[test] + fn test_mcp_server_acp_schema() { + let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap(); + assert!(json_contains_entry( + &mcp_server_schema, + "const", + &json!("acp") + )); + assert!(json_contains_entry( + &mcp_server_schema, + "$ref", + &json!("#/$defs/McpServerAcp") + )); + + let capabilities_schema = + serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap(); + assert!(json_contains_key(&capabilities_schema, "acp")); + } + + #[cfg(feature = "unstable_mcp_over_acp")] + fn json_contains_entry( + value: &serde_json::Value, + key: &str, + expected: &serde_json::Value, + ) -> bool { + match value { + serde_json::Value::Object(map) => { + map.get(key) == Some(expected) + || map + .values() + .any(|value| json_contains_entry(value, key, expected)) + } + serde_json::Value::Array(values) => values + .iter() + .any(|value| json_contains_entry(value, key, expected)), + _ => false, + } + } + + #[cfg(feature = "unstable_mcp_over_acp")] + fn json_contains_key(value: &serde_json::Value, key: &str) -> bool { + match value { + serde_json::Value::Object(map) => { + map.contains_key(key) || map.values().any(|value| json_contains_key(value, key)) + } + serde_json::Value::Array(values) => { + values.iter().any(|value| json_contains_key(value, key)) + } + _ => false, + } + } + #[test] fn test_mcp_server_sse_serialization() { let server = McpServer::Sse( @@ -5287,6 +5663,35 @@ mod test_serialization { assert!(matches!(deserialized, AuthMethod::Agent(_))); } + #[cfg(feature = "unstable_session_delete")] + #[test] + fn test_session_delete_serialization() { + assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete"); + assert_eq!( + ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(), + "session/delete" + ); + assert_eq!( + serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(), + json!({ + "sessionId": "sess_abc123" + }) + ); + assert_eq!( + serde_json::to_value(DeleteSessionResponse::new()).unwrap(), + json!({}) + ); + assert_eq!( + serde_json::to_value( + SessionCapabilities::new().delete(SessionDeleteCapabilities::new()) + ) + .unwrap(), + json!({ + "delete": {} + }) + ); + } + #[cfg(feature = "unstable_session_additional_directories")] #[test] fn test_session_additional_directories_serialization() { @@ -5314,13 +5719,6 @@ mod test_serialization { "mcpServers": [] }) ); - assert_eq!( - serde_json::to_value( - ListSessionsRequest::new().additional_directories(Vec::::new()) - ) - .unwrap(), - json!({}) - ); assert_eq!( serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(), json!({ @@ -5354,22 +5752,6 @@ mod test_serialization { .additional_directories, Vec::::new() ); - - assert_eq!( - serde_json::from_value::(json!({})) - .unwrap() - .additional_directories, - Vec::::new() - ); - - assert_eq!( - serde_json::from_value::(json!({ - "additionalDirectories": [] - })) - .unwrap() - .additional_directories, - Vec::::new() - ); } #[cfg(feature = "unstable_session_additional_directories")] @@ -6022,14 +6404,14 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_providers_request_serialization() { + fn test_set_provider_request_serialization() { use std::collections::HashMap; let mut headers = HashMap::new(); headers.insert("Authorization".to_string(), "Bearer sk-test".to_string()); let request = - SetProvidersRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1") + SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1") .headers(headers); let json = serde_json::to_value(&request).unwrap(); @@ -6045,7 +6427,7 @@ mod test_serialization { }) ); - let deserialized: SetProvidersRequest = serde_json::from_value(json).unwrap(); + let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap(); assert_eq!(deserialized.id, "main"); assert_eq!(deserialized.api_type, LlmProtocol::OpenAi); assert_eq!(deserialized.base_url, "https://api.openai.com/v1"); @@ -6058,9 +6440,9 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_providers_request_omits_empty_headers() { + fn test_set_provider_request_omits_empty_headers() { let request = - SetProvidersRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com"); + SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com"); let json = serde_json::to_value(&request).unwrap(); // headers should be omitted when empty @@ -6069,13 +6451,13 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_disable_providers_request_serialization() { - let request = DisableProvidersRequest::new("secondary"); + fn test_disable_provider_request_serialization() { + let request = DisableProviderRequest::new("secondary"); let json = serde_json::to_value(&request).unwrap(); assert_eq!(json, json!({ "id": "secondary" })); - let deserialized: DisableProvidersRequest = serde_json::from_value(json).unwrap(); + let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap(); assert_eq!(deserialized.id, "secondary"); } diff --git a/src/v1/client.rs b/src/v1/client.rs index e86b01dc8..e1c8e71aa 100644 --- a/src/v1/client.rs +++ b/src/v1/client.rs @@ -21,6 +21,13 @@ use crate::{ SkipListener, ToolCall, ToolCallUpdate, }; +#[cfg(feature = "unstable_mcp_over_acp")] +use super::mcp::{ + ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse, + MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME, + MessageMcpNotification, MessageMcpRequest, MessageMcpResponse, +}; + #[cfg(feature = "unstable_nes")] use crate::{ClientNesCapabilities, PositionEncodingKind}; @@ -1786,6 +1793,15 @@ pub struct ClientMethodNames { pub terminal_wait_for_exit: &'static str, /// Method for killing a terminal. pub terminal_kill: &'static str, + /// Method for opening an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_connect: &'static str, + /// Method for exchanging MCP-over-ACP messages. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_message: &'static str, + /// Method for closing an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_disconnect: &'static str, /// Method for elicitation. #[cfg(feature = "unstable_elicitation")] pub elicitation_create: &'static str, @@ -1805,6 +1821,12 @@ pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames { terminal_release: TERMINAL_RELEASE_METHOD_NAME, terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME, terminal_kill: TERMINAL_KILL_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_connect: MCP_CONNECT_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_message: MCP_MESSAGE_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_disconnect: MCP_DISCONNECT_METHOD_NAME, #[cfg(feature = "unstable_elicitation")] elicitation_create: ELICITATION_CREATE_METHOD_NAME, #[cfg(feature = "unstable_elicitation")] @@ -1931,6 +1953,27 @@ pub enum AgentRequest { /// Requests structured user input via a form or URL. #[cfg(feature = "unstable_elicitation")] CreateElicitationRequest(CreateElicitationRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Opens an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + ConnectMcpRequest(ConnectMcpRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Exchanges an MCP-over-ACP message. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpRequest(MessageMcpRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Closes an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + DisconnectMcpRequest(DisconnectMcpRequest), /// Handles extension method requests from the agent. /// /// Allows the Agent to send an arbitrary request that is not part of the ACP spec. @@ -1956,6 +1999,12 @@ impl AgentRequest { Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill, #[cfg(feature = "unstable_elicitation")] Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect, Self::ExtMethodRequest(ext_request) => &ext_request.method, } } @@ -1982,7 +2031,13 @@ pub enum ClientResponse { KillTerminalResponse(#[serde(default)] KillTerminalResponse), #[cfg(feature = "unstable_elicitation")] CreateElicitationResponse(CreateElicitationResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + ConnectMcpResponse(ConnectMcpResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse), ExtMethodResponse(ExtResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpResponse(MessageMcpResponse), } /// All possible notifications that an agent can send to a client. @@ -2016,6 +2071,13 @@ pub enum AgentNotification { /// Notification that a URL-based elicitation has completed. #[cfg(feature = "unstable_elicitation")] CompleteElicitationNotification(CompleteElicitationNotification), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Receives an MCP-over-ACP notification. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpNotification(MessageMcpNotification), /// Handles extension notifications from the agent. /// /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec. @@ -2034,6 +2096,8 @@ impl AgentNotification { Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update, #[cfg(feature = "unstable_elicitation")] Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message, Self::ExtNotification(ext_notification) => &ext_notification.method, } } @@ -2112,4 +2176,80 @@ mod tests { assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"])); } + + #[cfg(feature = "unstable_mcp_over_acp")] + #[test] + fn test_agent_mcp_request_method_names() { + use serde_json::json; + + let params: serde_json::Map = + [("cursor".to_string(), json!("abc"))].into_iter().collect(); + + assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect"); + assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message"); + assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect"); + + assert_eq!( + AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(), + "mcp/connect" + ); + assert_eq!( + AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list")) + .method(), + "mcp/message" + ); + assert_eq!( + AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(), + "mcp/disconnect" + ); + assert_eq!( + AgentNotification::MessageMcpNotification(MessageMcpNotification::new( + "conn-1", + "notifications/progress" + )) + .method(), + "mcp/message" + ); + + assert_eq!( + serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(), + json!({ "acpId": "server-1" }) + ); + assert_eq!( + serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(), + json!({ "connectionId": "conn-1" }) + ); + assert_eq!( + serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params)) + .unwrap(), + json!({ + "connectionId": "conn-1", + "method": "tools/list", + "params": { "cursor": "abc" } + }) + ); + assert_eq!( + serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(), + json!({ "connectionId": "conn-1" }) + ); + assert_eq!( + serde_json::to_value(MessageMcpNotification::new( + "conn-1", + "notifications/progress" + )) + .unwrap(), + json!({ + "connectionId": "conn-1", + "method": "notifications/progress" + }) + ); + + let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({ + "connectionId": "conn-1", + "method": "tools/list", + "params": null + })) + .unwrap(); + assert_eq!(request_with_null_params.params, None); + } } diff --git a/src/v1/content.rs b/src/v1/content.rs index 0f301bd82..fe19fe45b 100644 --- a/src/v1/content.rs +++ b/src/v1/content.rs @@ -57,6 +57,14 @@ pub enum ContentBlock { /// /// Requires the `embeddedContext` prompt capability when included in prompts. Resource(EmbeddedResource), + /// A template that supports variable substitution using `{{variable_name}}` syntax. + /// + /// Allows dynamic content generation by substituting variables into template strings. + /// Variables are resolved at processing time and can include values from context, + /// user input, or system state. + /// + /// Requires the `promptVariables` prompt capability when included in prompts. + PromptTemplate(PromptTemplateContent), } /// Text provided to or from an LLM. @@ -518,6 +526,201 @@ pub enum Role { User, } +/// A template content block that supports variable substitution. +/// +/// Templates use `{{variable_name}}` syntax for variable placeholders that can be +/// substituted with actual values at processing time. This enables dynamic content +/// generation and reusable prompt templates. +#[serde_as] +#[skip_serializing_none] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[non_exhaustive] +pub struct PromptTemplateContent { + #[serde_as(deserialize_as = "DefaultOnError")] + #[serde(default)] + pub annotations: Option, + /// The template string with `{{variable_name}}` placeholders. + pub template: String, + /// Variables available for substitution in this template. + pub variables: Vec, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl PromptTemplateContent { + #[must_use] + pub fn new(template: impl Into, variables: Vec) -> Self { + Self { + annotations: None, + template: template.into(), + variables, + meta: None, + } + } + + #[must_use] + pub fn annotations(mut self, annotations: impl IntoOption) -> Self { + self.annotations = annotations.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } + + /// Substitute variables in the template and return the resolved text. + /// + /// This method processes the template string and replaces `{{variable_name}}` + /// placeholders with their corresponding values from the variables vector. + /// If a variable is not found or has no value, the placeholder is left unchanged. + #[must_use] + pub fn substitute(&self) -> String { + let mut result = self.template.clone(); + + for variable in &self.variables { + if let Some(value) = &variable.value { + let placeholder = format!("{{{{{}}}}}", variable.name); + result = result.replace(&placeholder, value); + } + } + + result + } +} + +/// A variable that can be substituted in a prompt template. +/// +/// Variables define named placeholders that can be replaced with actual values +/// during template processing. They can include metadata about expected types, +/// descriptions for user interfaces, and validation constraints. +#[serde_as] +#[skip_serializing_none] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[non_exhaustive] +pub struct PromptVariable { + /// The variable name (used in `{{variable_name}}` placeholders). + pub name: String, + /// The current value of the variable (if set). + pub value: Option, + /// Human-readable description of this variable. + pub description: Option, + /// The expected type of this variable's value. + #[serde(rename = "type")] + pub variable_type: Option, + /// Whether this variable is required for template processing. + #[serde(default)] + pub required: bool, + /// Default value to use if no value is provided. + pub default_value: Option, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl PromptVariable { + #[must_use] + pub fn new(name: impl Into) -> Self { + Self { + name: name.into(), + value: None, + description: None, + variable_type: None, + required: false, + default_value: None, + meta: None, + } + } + + #[must_use] + pub fn value(mut self, value: impl IntoOption) -> Self { + self.value = value.into_option(); + self + } + + #[must_use] + pub fn description(mut self, description: impl IntoOption) -> Self { + self.description = description.into_option(); + self + } + + #[must_use] + pub fn variable_type(mut self, variable_type: impl IntoOption) -> Self { + self.variable_type = variable_type.into_option(); + self + } + + #[must_use] + pub fn required(mut self, required: bool) -> Self { + self.required = required; + self + } + + #[must_use] + pub fn default_value(mut self, default_value: impl IntoOption) -> Self { + self.default_value = default_value.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } + + /// Get the effective value for this variable, considering default values. + #[must_use] + pub fn effective_value(&self) -> Option<&String> { + self.value.as_ref().or(self.default_value.as_ref()) + } +} + +/// The expected type of a prompt variable's value. +/// +/// This helps clients provide appropriate input interfaces and validation +/// for prompt variables. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum PromptVariableType { + /// A string value (default if not specified). + String, + /// A numeric value (integer or float). + Number, + /// A boolean value (true/false). + Boolean, + /// A date/time value in ISO 8601 format. + DateTime, + /// A URL or URI reference. + Url, + /// An email address. + Email, + /// A multiline text value. + Text, + /// A value selected from a predefined list (enum-like). + Select { options: Vec }, +} + #[cfg(test)] mod tests { use super::*; @@ -586,4 +789,55 @@ mod tests { assert!(!json.as_object().unwrap().contains_key("annotations")); assert!(!json.as_object().unwrap().contains_key("meta")); } + + #[test] + fn test_prompt_variable_creation() { + let var = PromptVariable::new("username") + .value("alice") + .description("The user's name") + .variable_type(PromptVariableType::String) + .required(true); + + assert_eq!(var.name, "username"); + assert_eq!(var.value, Some("alice".to_string())); + assert_eq!(var.description, Some("The user's name".to_string())); + assert_eq!(var.variable_type, Some(PromptVariableType::String)); + assert!(var.required); + } + + #[test] + fn test_prompt_template_substitution() { + let variables = vec![ + PromptVariable::new("name").value("Alice"), + PromptVariable::new("task").value("code review"), + ]; + + let template = + PromptTemplateContent::new("Hello {{name}}, please help me with {{task}}.", variables); + + let result = template.substitute(); + assert_eq!(result, "Hello Alice, please help me with code review."); + } + + #[test] + fn test_content_block_prompt_template_v1() { + let variables = vec![PromptVariable::new("language").value("Rust")]; + let template_content = PromptTemplateContent::new("Write {{language}} code", variables); + let content_block = ContentBlock::PromptTemplate(template_content); + + // Test serialization + let json = serde_json::to_value(&content_block).unwrap(); + assert_eq!(json["type"], "prompt_template"); + assert_eq!(json["template"], "Write {{language}} code"); + + // Test deserialization + let parsed: ContentBlock = serde_json::from_value(json).unwrap(); + if let ContentBlock::PromptTemplate(template) = parsed { + assert_eq!(template.template, "Write {{language}} code"); + assert_eq!(template.variables.len(), 1); + assert_eq!(template.variables[0].name, "language"); + } else { + panic!("Expected PromptTemplate variant"); + } + } } diff --git a/src/v1/mcp.rs b/src/v1/mcp.rs new file mode 100644 index 000000000..7f2be29c2 --- /dev/null +++ b/src/v1/mcp.rs @@ -0,0 +1,354 @@ +//! MCP-over-ACP transport types. + +use std::sync::Arc; + +use derive_more::{Display, From}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::value::RawValue; +use serde_with::skip_serializing_none; + +use crate::{IntoOption, McpServerAcpId, Meta}; + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// A unique identifier for an active MCP-over-ACP connection. +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)] +#[serde(transparent)] +#[from(Arc, String, &'static str)] +#[non_exhaustive] +pub struct McpConnectionId(pub Arc); + +impl McpConnectionId { + #[must_use] + pub fn new(id: impl Into>) -> Self { + Self(id.into()) + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for `mcp/connect`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct ConnectMcpRequest { + /// The ACP MCP server ID that was provided by the component declaring the MCP server. + pub acp_id: McpServerAcpId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl ConnectMcpRequest { + #[must_use] + pub fn new(acp_id: impl Into) -> Self { + Self { + acp_id: acp_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `mcp/connect`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct ConnectMcpResponse { + /// The unique identifier for this MCP-over-ACP connection. + pub connection_id: McpConnectionId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl ConnectMcpResponse { + #[must_use] + pub fn new(connection_id: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for `mcp/message`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))] +#[non_exhaustive] +pub struct MessageMcpRequest { + /// The MCP-over-ACP connection this message is sent on. + pub connection_id: McpConnectionId, + /// The inner MCP method name. + pub method: String, + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[serde(default)] + pub params: Option>, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl MessageMcpRequest { + #[must_use] + pub fn new(connection_id: impl Into, method: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + method: method.into(), + params: None, + meta: None, + } + } + + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[must_use] + pub fn params( + mut self, + params: impl IntoOption>, + ) -> Self { + self.params = params.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Notification parameters for `mcp/message`. +/// +/// This is used when the wrapped MCP message is a notification and the outer JSON-RPC +/// envelope has no `id`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))] +#[non_exhaustive] +pub struct MessageMcpNotification { + /// The MCP-over-ACP connection this message is sent on. + pub connection_id: McpConnectionId, + /// The inner MCP method name. + pub method: String, + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[serde(default)] + pub params: Option>, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl MessageMcpNotification { + #[must_use] + pub fn new(connection_id: impl Into, method: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + method: method.into(), + params: None, + meta: None, + } + } + + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[must_use] + pub fn params( + mut self, + params: impl IntoOption>, + ) -> Self { + self.params = params.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `mcp/message`. +/// +/// This is the inner MCP response result payload. Any JSON value is valid. +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, From)] +#[serde(transparent)] +#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))] +#[non_exhaustive] +pub struct MessageMcpResponse(#[schemars(with = "serde_json::Value")] pub Arc); + +impl MessageMcpResponse { + #[must_use] + pub fn new(result: Arc) -> Self { + Self(result) + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for `mcp/disconnect`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct DisconnectMcpRequest { + /// The MCP-over-ACP connection to close. + pub connection_id: McpConnectionId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl DisconnectMcpRequest { + #[must_use] + pub fn new(connection_id: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `mcp/disconnect`. +#[skip_serializing_none] +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct DisconnectMcpResponse { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl DisconnectMcpResponse { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// Method name for opening an MCP-over-ACP connection. +pub(crate) const MCP_CONNECT_METHOD_NAME: &str = "mcp/connect"; +/// Method name for exchanging MCP-over-ACP messages. +pub(crate) const MCP_MESSAGE_METHOD_NAME: &str = "mcp/message"; +/// Method name for closing an MCP-over-ACP connection. +pub(crate) const MCP_DISCONNECT_METHOD_NAME: &str = "mcp/disconnect"; diff --git a/src/v1/mod.rs b/src/v1/mod.rs index caadb75c1..d076de19d 100644 --- a/src/v1/mod.rs +++ b/src/v1/mod.rs @@ -7,6 +7,8 @@ mod content; mod elicitation; mod error; mod ext; +#[cfg(feature = "unstable_mcp_over_acp")] +mod mcp; #[cfg(feature = "unstable_nes")] mod nes; mod plan; @@ -23,6 +25,8 @@ use derive_more::{Display, From}; pub use elicitation::*; pub use error::*; pub use ext::*; +#[cfg(feature = "unstable_mcp_over_acp")] +pub use mcp::*; #[cfg(feature = "unstable_nes")] pub use nes::*; pub use plan::*; diff --git a/src/v2/agent.rs b/src/v2/agent.rs index e7322fd6d..d6b47786b 100644 --- a/src/v2/agent.rs +++ b/src/v2/agent.rs @@ -18,6 +18,11 @@ use super::{ }; use crate::{IntoOption, ProtocolVersion, SkipListener}; +#[cfg(feature = "unstable_mcp_over_acp")] +use super::mcp::{ + MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse, +}; + #[cfg(feature = "unstable_nes")] use super::{ AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification, @@ -330,14 +335,9 @@ impl AuthenticateResponse { // Logout -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Request parameters for the logout method. /// /// Terminates the current authenticated session. -#[cfg(feature = "unstable_logout")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))] @@ -353,7 +353,6 @@ pub struct LogoutRequest { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl LogoutRequest { #[must_use] pub fn new() -> Self { @@ -372,12 +371,7 @@ impl LogoutRequest { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Response to the `logout` method. -#[cfg(feature = "unstable_logout")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))] @@ -393,7 +387,6 @@ pub struct LogoutResponse { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl LogoutResponse { #[must_use] pub fn new() -> Self { @@ -412,12 +405,7 @@ impl LogoutResponse { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Authentication-related capabilities supported by the agent. -#[cfg(feature = "unstable_logout")] #[serde_as] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -439,7 +427,6 @@ pub struct AgentAuthCapabilities { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl AgentAuthCapabilities { #[must_use] pub fn new() -> Self { @@ -465,14 +452,9 @@ impl AgentAuthCapabilities { } } -/// **UNSTABLE** -/// -/// This capability is not part of the spec yet, and may be removed or changed at any point. -/// /// Logout capabilities supported by the agent. /// /// By supplying `{}` it means that the agent supports the logout method. -#[cfg(feature = "unstable_logout")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive] @@ -486,7 +468,6 @@ pub struct LogoutCapabilities { pub meta: Option, } -#[cfg(feature = "unstable_logout")] impl LogoutCapabilities { #[must_use] pub fn new() -> Self { @@ -1115,7 +1096,8 @@ pub struct LoadSessionRequest { /// /// When omitted or empty, no additional roots are activated. When non-empty, /// this is the complete resulting additional-root list for the loaded - /// session. + /// session. It may differ from any previously used or reported list as long as + /// the request `cwd` matches the session's `cwd`. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1477,7 +1459,8 @@ pub struct ResumeSessionRequest { /// /// When omitted or empty, no additional roots are activated. When non-empty, /// this is the complete resulting additional-root list for the resumed - /// session. + /// session. It may differ from any previously used or reported list as long as + /// the request `cwd` matches the session's `cwd`. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1716,17 +1699,6 @@ impl CloseSessionResponse { pub struct ListSessionsRequest { /// Filter sessions by working directory. Must be an absolute path. pub cwd: Option, - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// - /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - /// - /// This filter applies only when the field is present and non-empty. When - /// omitted or empty, no additional-root filter is applied. - #[cfg(feature = "unstable_session_additional_directories")] - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub additional_directories: Vec, /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination pub cursor: Option, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -1751,18 +1723,6 @@ impl ListSessionsRequest { self } - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// - /// Filter sessions by the exact ordered additional workspace roots. Each path must be absolute. - #[cfg(feature = "unstable_session_additional_directories")] - #[must_use] - pub fn additional_directories(mut self, additional_directories: Vec) -> Self { - self.additional_directories = additional_directories; - self - } - /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination #[must_use] pub fn cursor(mut self, cursor: impl IntoOption) -> Self { @@ -1833,6 +1793,95 @@ impl ListSessionsResponse { } } +// Delete session + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for deleting an existing session from `session/list`. +/// +/// Only available if the Agent supports the `sessionCapabilities.delete` capability. +#[cfg(feature = "unstable_session_delete")] +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct DeleteSessionRequest { + /// The ID of the session to delete. + pub session_id: SessionId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_session_delete")] +impl DeleteSessionRequest { + #[must_use] + pub fn new(session_id: impl Into) -> Self { + Self { + session_id: session_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response from deleting a session. +#[cfg(feature = "unstable_session_delete")] +#[skip_serializing_none] +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct DeleteSessionResponse { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_session_delete")] +impl DeleteSessionResponse { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + /// Information about a session returned by session/list #[serde_as] #[skip_serializing_none] @@ -1848,9 +1897,11 @@ pub struct SessionInfo { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + /// Additional workspace roots reported for this session. Each path must be absolute. /// - /// When omitted or empty, there are no additional roots for the session. + /// When present, this is the complete ordered additional-root list reported + /// by the Agent. Omitted and empty values are equivalent: the response + /// reports no additional roots. #[cfg(feature = "unstable_session_additional_directories")] #[serde(default, skip_serializing_if = "Vec::is_empty")] pub additional_directories: Vec, @@ -1890,7 +1941,7 @@ impl SessionInfo { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Authoritative ordered additional workspace roots for this session. Each path must be absolute. + /// Additional workspace roots reported for this session. Each path must be absolute. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories(mut self, additional_directories: Vec) -> Self { @@ -2689,6 +2740,16 @@ pub enum McpServer { /// /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`. Sse(McpServerSse), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// ACP transport configuration + /// + /// Only available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`. + /// The MCP server is provided by an ACP component and communicates over the ACP channel. + #[cfg(feature = "unstable_mcp_over_acp")] + Acp(McpServerAcp), /// Stdio transport configuration /// /// All Agents MUST support this transport. @@ -2798,6 +2859,83 @@ impl McpServerSse { } } +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Unique identifier for an MCP server using the ACP transport. +/// +/// The value is opaque and generated by the ACP component providing the MCP server. It is +/// used by `mcp/connect` to route connection requests back to the component that declared the +/// server. +#[cfg(feature = "unstable_mcp_over_acp")] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)] +#[serde(transparent)] +#[from(Arc, String, &'static str)] +#[non_exhaustive] +pub struct McpServerAcpId(pub Arc); + +#[cfg(feature = "unstable_mcp_over_acp")] +impl McpServerAcpId { + #[must_use] + pub fn new(id: impl Into>) -> Self { + Self(id.into()) + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// ACP transport configuration for MCP. +/// +/// The MCP server is provided by an ACP component and communicates over the ACP channel +/// using `mcp/connect`, `mcp/message`, and `mcp/disconnect`. +#[skip_serializing_none] +#[cfg(feature = "unstable_mcp_over_acp")] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[non_exhaustive] +pub struct McpServerAcp { + /// Human-readable name identifying this MCP server. + pub name: String, + /// Unique identifier for this MCP server, generated by the component providing it. + /// + /// Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible + /// on the same ACP connection. + pub id: McpServerAcpId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl McpServerAcp { + #[must_use] + pub fn new(name: impl Into, id: impl Into) -> Self { + Self { + name: name.into(), + id: id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + /// Stdio transport configuration for MCP. #[skip_serializing_none] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -3652,7 +3790,7 @@ impl ListProvidersResponse { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProvidersRequest { +pub struct SetProviderRequest { /// Provider id to configure. pub id: String, /// Protocol type for this provider. @@ -3673,7 +3811,7 @@ pub struct SetProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl SetProvidersRequest { +impl SetProviderRequest { #[must_use] pub fn new(id: impl Into, api_type: LlmProtocol, base_url: impl Into) -> Self { Self { @@ -3716,7 +3854,7 @@ impl SetProvidersRequest { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct SetProvidersResponse { +pub struct SetProviderResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3727,7 +3865,7 @@ pub struct SetProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl SetProvidersResponse { +impl SetProviderResponse { #[must_use] pub fn new() -> Self { Self::default() @@ -3756,7 +3894,7 @@ impl SetProvidersResponse { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProvidersRequest { +pub struct DisableProviderRequest { /// Provider id to disable. pub id: String, /// The _meta property is reserved by ACP to allow clients and agents to attach additional @@ -3769,7 +3907,7 @@ pub struct DisableProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProvidersRequest { +impl DisableProviderRequest { #[must_use] pub fn new(id: impl Into) -> Self { Self { @@ -3801,7 +3939,7 @@ impl DisableProvidersRequest { #[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct DisableProvidersResponse { +pub struct DisableProviderResponse { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -3812,7 +3950,7 @@ pub struct DisableProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl DisableProvidersResponse { +impl DisableProviderResponse { #[must_use] pub fn new() -> Self { Self::default() @@ -3855,12 +3993,7 @@ pub struct AgentCapabilities { pub mcp_capabilities: McpCapabilities, #[serde(default)] pub session_capabilities: SessionCapabilities, - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// /// Authentication-related capabilities supported by the agent. - #[cfg(feature = "unstable_logout")] #[serde(default)] pub auth: AgentAuthCapabilities, /// **UNSTABLE** @@ -3935,12 +4068,7 @@ impl AgentCapabilities { self } - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// /// Authentication-related capabilities supported by the agent. - #[cfg(feature = "unstable_logout")] #[must_use] pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self { self.auth = auth; @@ -4059,7 +4187,23 @@ pub struct SessionCapabilities { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. + /// Whether the agent supports `session/delete`. + /// + /// Optional. Omitted or `null` both mean the agent does not advertise support. + /// Supplying `{}` means the agent supports deleting sessions from `session/list`. + #[cfg(feature = "unstable_session_delete")] + #[serde_as(deserialize_as = "DefaultOnError")] + #[serde(default)] + pub delete: Option, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests. + /// + /// Agents that also support `session/list` may return + /// `SessionInfo.additionalDirectories` to report the complete ordered + /// additional-root list associated with a listed session. #[cfg(feature = "unstable_session_additional_directories")] #[serde_as(deserialize_as = "DefaultOnError")] #[serde(default)] @@ -4107,7 +4251,26 @@ impl SessionCapabilities { /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// - /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests and `session/list`. + /// Whether the agent supports `session/delete`. + /// + /// Omitted or `null` both mean the agent does not advertise support. + /// Supplying `{}` means the agent supports deleting sessions from `session/list`. + #[cfg(feature = "unstable_session_delete")] + #[must_use] + pub fn delete(mut self, delete: impl IntoOption) -> Self { + self.delete = delete.into_option(); + self + } + + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests. + /// + /// Agents that also support `session/list` may return + /// `SessionInfo.additionalDirectories` to report the complete ordered + /// additional-root list associated with a listed session. #[cfg(feature = "unstable_session_additional_directories")] #[must_use] pub fn additional_directories( @@ -4186,14 +4349,56 @@ impl SessionListCapabilities { } } +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Capabilities for the `session/delete` method. +/// +/// Supplying `{}` means the agent supports deleting sessions from `session/list`. +#[cfg(feature = "unstable_session_delete")] +#[skip_serializing_none] +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[non_exhaustive] +pub struct SessionDeleteCapabilities { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +#[cfg(feature = "unstable_session_delete")] +impl SessionDeleteCapabilities { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Capabilities for additional session directories support. /// -/// By supplying `{}` it means that the agent supports the `additionalDirectories` field on -/// supported session lifecycle requests and `session/list`. +/// By supplying `{}` it means that the agent supports the `additionalDirectories` +/// field on supported session lifecycle requests. Agents that also support +/// `session/list` may return `SessionInfo.additionalDirectories` to report the +/// complete ordered additional-root list associated with a listed session. #[cfg(feature = "unstable_session_additional_directories")] #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] @@ -4351,6 +4556,7 @@ impl SessionCloseCapabilities { #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "camelCase")] #[non_exhaustive] +#[allow(clippy::struct_excessive_bools)] pub struct PromptCapabilities { /// Agent supports [`ContentBlock::Image`]. #[serde(default)] @@ -4364,6 +4570,12 @@ pub struct PromptCapabilities { /// in prompt requests for pieces of context that are referenced in the message. #[serde(default)] pub embedded_context: bool, + /// Agent supports prompt variables and templates in `session/prompt` requests. + /// + /// When enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`] + /// in prompt requests with variable substitution support. + #[serde(default)] + pub prompt_variables: bool, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4403,6 +4615,16 @@ impl PromptCapabilities { self } + /// Agent supports prompt variables and templates in `session/prompt` requests. + /// + /// When enabled, the Client is allowed to include [`ContentBlock::PromptTemplate`] + /// in prompt requests with variable substitution support. + #[must_use] + pub fn prompt_variables(mut self, prompt_variables: bool) -> Self { + self.prompt_variables = prompt_variables; + self + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4427,6 +4649,14 @@ pub struct McpCapabilities { /// Agent supports [`McpServer::Sse`]. #[serde(default)] pub sse: bool, + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Agent supports [`McpServer::Acp`]. + #[cfg(feature = "unstable_mcp_over_acp")] + #[serde(default)] + pub acp: bool, /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4456,6 +4686,18 @@ impl McpCapabilities { self } + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Agent supports [`McpServer::Acp`]. + #[cfg(feature = "unstable_mcp_over_acp")] + #[must_use] + pub fn acp(mut self, acp: bool) -> Self { + self.acp = acp; + self + } + /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4501,11 +4743,17 @@ pub struct AgentMethodNames { pub session_prompt: &'static str, /// Notification for cancelling operations. pub session_cancel: &'static str, + /// Method for exchanging MCP-over-ACP messages. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_message: &'static str, /// Method for selecting a model for a given session. #[cfg(feature = "unstable_session_model")] pub session_set_model: &'static str, /// Method for listing existing sessions. pub session_list: &'static str, + /// Method for deleting an existing session. + #[cfg(feature = "unstable_session_delete")] + pub session_delete: &'static str, /// Method for forking an existing session. #[cfg(feature = "unstable_session_fork")] pub session_fork: &'static str, @@ -4514,7 +4762,6 @@ pub struct AgentMethodNames { /// Method for closing an active session. pub session_close: &'static str, /// Method for logging out of an authenticated session. - #[cfg(feature = "unstable_logout")] pub logout: &'static str, /// Method for starting an NES session. #[cfg(feature = "unstable_nes")] @@ -4564,14 +4811,17 @@ pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames { session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME, session_prompt: SESSION_PROMPT_METHOD_NAME, session_cancel: SESSION_CANCEL_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_message: MCP_MESSAGE_METHOD_NAME, #[cfg(feature = "unstable_session_model")] session_set_model: SESSION_SET_MODEL_METHOD_NAME, session_list: SESSION_LIST_METHOD_NAME, + #[cfg(feature = "unstable_session_delete")] + session_delete: SESSION_DELETE_METHOD_NAME, #[cfg(feature = "unstable_session_fork")] session_fork: SESSION_FORK_METHOD_NAME, session_resume: SESSION_RESUME_METHOD_NAME, session_close: SESSION_CLOSE_METHOD_NAME, - #[cfg(feature = "unstable_logout")] logout: LOGOUT_METHOD_NAME, #[cfg(feature = "unstable_nes")] nes_start: NES_START_METHOD_NAME, @@ -4625,6 +4875,9 @@ pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel"; pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model"; /// Method name for listing existing sessions. pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list"; +/// Method name for deleting an existing session. +#[cfg(feature = "unstable_session_delete")] +pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete"; /// Method name for forking an existing session. #[cfg(feature = "unstable_session_fork")] pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork"; @@ -4633,7 +4886,6 @@ pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume"; /// Method name for closing an active session. pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close"; /// Method name for logging out of an authenticated session. -#[cfg(feature = "unstable_logout")] pub(crate) const LOGOUT_METHOD_NAME: &str = "logout"; /// All possible requests that a client can send to an agent. @@ -4682,23 +4934,18 @@ pub enum ClientRequest { /// /// Replaces the configuration for a provider. #[cfg(feature = "unstable_llm_providers")] - SetProvidersRequest(SetProvidersRequest), + SetProviderRequest(SetProviderRequest), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. /// /// Disables a provider. #[cfg(feature = "unstable_llm_providers")] - DisableProvidersRequest(DisableProvidersRequest), - /// **UNSTABLE** - /// - /// This capability is not part of the spec yet, and may be removed or changed at any point. - /// + DisableProviderRequest(DisableProviderRequest), /// Logs out of the current authenticated state. /// /// After a successful logout, all new sessions will require authentication. /// There is no guarantee about the behavior of already running sessions. - #[cfg(feature = "unstable_logout")] LogoutRequest(LogoutRequest), /// Creates a new conversation session with the agent. /// @@ -4730,6 +4977,15 @@ pub enum ClientRequest { /// /// The agent should return metadata about sessions with optional filtering and pagination support. ListSessionsRequest(ListSessionsRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Deletes an existing session from `session/list`. + /// + /// This method is only available if the agent advertises the `sessionCapabilities.delete` capability. + #[cfg(feature = "unstable_session_delete")] + DeleteSessionRequest(DeleteSessionRequest), #[cfg(feature = "unstable_session_fork")] /// **UNSTABLE** /// @@ -4816,6 +5072,13 @@ pub enum ClientRequest { /// The agent must cancel any ongoing work and then free up any resources /// associated with the NES session. CloseNesRequest(CloseNesRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Exchanges an MCP-over-ACP message. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpRequest(MessageMcpRequest), /// Handles extension method requests from the client. /// /// Extension methods provide a way to add custom functionality while maintaining @@ -4835,14 +5098,15 @@ impl ClientRequest { #[cfg(feature = "unstable_llm_providers")] Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list, #[cfg(feature = "unstable_llm_providers")] - Self::SetProvidersRequest(_) => AGENT_METHOD_NAMES.providers_set, + Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set, #[cfg(feature = "unstable_llm_providers")] - Self::DisableProvidersRequest(_) => AGENT_METHOD_NAMES.providers_disable, - #[cfg(feature = "unstable_logout")] + Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable, Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout, Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new, Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load, Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list, + #[cfg(feature = "unstable_session_delete")] + Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete, #[cfg(feature = "unstable_session_fork")] Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork, Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume, @@ -4858,6 +5122,8 @@ impl ClientRequest { Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest, #[cfg(feature = "unstable_nes")] Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message, Self::ExtMethodRequest(ext_request) => &ext_request.method, } } @@ -4880,14 +5146,15 @@ pub enum AgentResponse { #[cfg(feature = "unstable_llm_providers")] ListProvidersResponse(ListProvidersResponse), #[cfg(feature = "unstable_llm_providers")] - SetProvidersResponse(#[serde(default)] SetProvidersResponse), + SetProviderResponse(#[serde(default)] SetProviderResponse), #[cfg(feature = "unstable_llm_providers")] - DisableProvidersResponse(#[serde(default)] DisableProvidersResponse), - #[cfg(feature = "unstable_logout")] + DisableProviderResponse(#[serde(default)] DisableProviderResponse), LogoutResponse(#[serde(default)] LogoutResponse), NewSessionResponse(NewSessionResponse), LoadSessionResponse(#[serde(default)] LoadSessionResponse), ListSessionsResponse(ListSessionsResponse), + #[cfg(feature = "unstable_session_delete")] + DeleteSessionResponse(#[serde(default)] DeleteSessionResponse), #[cfg(feature = "unstable_session_fork")] ForkSessionResponse(ForkSessionResponse), ResumeSessionResponse(#[serde(default)] ResumeSessionResponse), @@ -4904,6 +5171,8 @@ pub enum AgentResponse { #[cfg(feature = "unstable_nes")] CloseNesResponse(#[serde(default)] CloseNesResponse), ExtMethodResponse(ExtResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpResponse(MessageMcpResponse), } /// All possible notifications that a client can send to an agent. @@ -4964,6 +5233,13 @@ pub enum ClientNotification { /// /// Notification sent when a suggestion is rejected. RejectNesNotification(RejectNesNotification), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Sends an MCP-over-ACP notification. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpNotification(MessageMcpNotification), /// Handles extension notifications from the client. /// /// Extension notifications provide a way to send one-way messages for custom functionality @@ -4993,6 +5269,8 @@ impl ClientNotification { Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept, #[cfg(feature = "unstable_nes")] Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message, Self::ExtNotification(ext_notification) => &ext_notification.method, } } @@ -5137,6 +5415,26 @@ mod test_serialization { } } + #[cfg(feature = "unstable_mcp_over_acp")] + #[test] + fn test_client_mcp_message_method_names() { + assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message"); + + assert_eq!( + ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list")) + .method(), + "mcp/message" + ); + assert_eq!( + ClientNotification::MessageMcpNotification(MessageMcpNotification::new( + "conn-1", + "notifications/progress" + )) + .method(), + "mcp/message" + ); + } + #[test] fn test_mcp_server_sse_serialization() { let server = McpServer::Sse( @@ -5287,6 +5585,35 @@ mod test_serialization { assert!(matches!(deserialized, AuthMethod::Agent(_))); } + #[cfg(feature = "unstable_session_delete")] + #[test] + fn test_session_delete_serialization() { + assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete"); + assert_eq!( + ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(), + "session/delete" + ); + assert_eq!( + serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(), + json!({ + "sessionId": "sess_abc123" + }) + ); + assert_eq!( + serde_json::to_value(DeleteSessionResponse::new()).unwrap(), + json!({}) + ); + assert_eq!( + serde_json::to_value( + SessionCapabilities::new().delete(SessionDeleteCapabilities::new()) + ) + .unwrap(), + json!({ + "delete": {} + }) + ); + } + #[cfg(feature = "unstable_session_additional_directories")] #[test] fn test_session_additional_directories_serialization() { @@ -5314,13 +5641,6 @@ mod test_serialization { "mcpServers": [] }) ); - assert_eq!( - serde_json::to_value( - ListSessionsRequest::new().additional_directories(Vec::::new()) - ) - .unwrap(), - json!({}) - ); assert_eq!( serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(), json!({ @@ -5354,22 +5674,6 @@ mod test_serialization { .additional_directories, Vec::::new() ); - - assert_eq!( - serde_json::from_value::(json!({})) - .unwrap() - .additional_directories, - Vec::::new() - ); - - assert_eq!( - serde_json::from_value::(json!({ - "additionalDirectories": [] - })) - .unwrap() - .additional_directories, - Vec::::new() - ); } #[cfg(feature = "unstable_session_additional_directories")] @@ -6022,14 +6326,14 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_providers_request_serialization() { + fn test_set_provider_request_serialization() { use std::collections::HashMap; let mut headers = HashMap::new(); headers.insert("Authorization".to_string(), "Bearer sk-test".to_string()); let request = - SetProvidersRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1") + SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1") .headers(headers); let json = serde_json::to_value(&request).unwrap(); @@ -6045,7 +6349,7 @@ mod test_serialization { }) ); - let deserialized: SetProvidersRequest = serde_json::from_value(json).unwrap(); + let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap(); assert_eq!(deserialized.id, "main"); assert_eq!(deserialized.api_type, LlmProtocol::OpenAi); assert_eq!(deserialized.base_url, "https://api.openai.com/v1"); @@ -6058,9 +6362,9 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_set_providers_request_omits_empty_headers() { + fn test_set_provider_request_omits_empty_headers() { let request = - SetProvidersRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com"); + SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com"); let json = serde_json::to_value(&request).unwrap(); // headers should be omitted when empty @@ -6069,13 +6373,13 @@ mod test_serialization { #[cfg(feature = "unstable_llm_providers")] #[test] - fn test_disable_providers_request_serialization() { - let request = DisableProvidersRequest::new("secondary"); + fn test_disable_provider_request_serialization() { + let request = DisableProviderRequest::new("secondary"); let json = serde_json::to_value(&request).unwrap(); assert_eq!(json, json!({ "id": "secondary" })); - let deserialized: DisableProvidersRequest = serde_json::from_value(json).unwrap(); + let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap(); assert_eq!(deserialized.id, "secondary"); } diff --git a/src/v2/client.rs b/src/v2/client.rs index e88b5a943..001408d8d 100644 --- a/src/v2/client.rs +++ b/src/v2/client.rs @@ -21,6 +21,13 @@ use super::{ }; use crate::{IntoMaybeUndefined, IntoOption, MaybeUndefined, SkipListener}; +#[cfg(feature = "unstable_mcp_over_acp")] +use super::mcp::{ + ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse, + MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME, + MessageMcpNotification, MessageMcpRequest, MessageMcpResponse, +}; + #[cfg(feature = "unstable_nes")] use super::{ClientNesCapabilities, PositionEncodingKind}; @@ -1786,6 +1793,15 @@ pub struct ClientMethodNames { pub terminal_wait_for_exit: &'static str, /// Method for killing a terminal. pub terminal_kill: &'static str, + /// Method for opening an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_connect: &'static str, + /// Method for exchanging MCP-over-ACP messages. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_message: &'static str, + /// Method for closing an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + pub mcp_disconnect: &'static str, /// Method for elicitation. #[cfg(feature = "unstable_elicitation")] pub elicitation_create: &'static str, @@ -1805,6 +1821,12 @@ pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames { terminal_release: TERMINAL_RELEASE_METHOD_NAME, terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME, terminal_kill: TERMINAL_KILL_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_connect: MCP_CONNECT_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_message: MCP_MESSAGE_METHOD_NAME, + #[cfg(feature = "unstable_mcp_over_acp")] + mcp_disconnect: MCP_DISCONNECT_METHOD_NAME, #[cfg(feature = "unstable_elicitation")] elicitation_create: ELICITATION_CREATE_METHOD_NAME, #[cfg(feature = "unstable_elicitation")] @@ -1931,6 +1953,27 @@ pub enum AgentRequest { /// Requests structured user input via a form or URL. #[cfg(feature = "unstable_elicitation")] CreateElicitationRequest(CreateElicitationRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Opens an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + ConnectMcpRequest(ConnectMcpRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Exchanges an MCP-over-ACP message. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpRequest(MessageMcpRequest), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Closes an MCP-over-ACP connection. + #[cfg(feature = "unstable_mcp_over_acp")] + DisconnectMcpRequest(DisconnectMcpRequest), /// Handles extension method requests from the agent. /// /// Allows the Agent to send an arbitrary request that is not part of the ACP spec. @@ -1956,6 +1999,12 @@ impl AgentRequest { Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill, #[cfg(feature = "unstable_elicitation")] Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect, Self::ExtMethodRequest(ext_request) => &ext_request.method, } } @@ -1982,7 +2031,13 @@ pub enum ClientResponse { KillTerminalResponse(#[serde(default)] KillTerminalResponse), #[cfg(feature = "unstable_elicitation")] CreateElicitationResponse(CreateElicitationResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + ConnectMcpResponse(ConnectMcpResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse), ExtMethodResponse(ExtResponse), + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpResponse(MessageMcpResponse), } /// All possible notifications that an agent can send to a client. @@ -2016,6 +2071,13 @@ pub enum AgentNotification { /// Notification that a URL-based elicitation has completed. #[cfg(feature = "unstable_elicitation")] CompleteElicitationNotification(CompleteElicitationNotification), + /// **UNSTABLE** + /// + /// This capability is not part of the spec yet, and may be removed or changed at any point. + /// + /// Receives an MCP-over-ACP notification. + #[cfg(feature = "unstable_mcp_over_acp")] + MessageMcpNotification(MessageMcpNotification), /// Handles extension notifications from the agent. /// /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec. @@ -2034,6 +2096,8 @@ impl AgentNotification { Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update, #[cfg(feature = "unstable_elicitation")] Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete, + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message, Self::ExtNotification(ext_notification) => &ext_notification.method, } } @@ -2112,4 +2176,80 @@ mod tests { assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"])); } + + #[cfg(feature = "unstable_mcp_over_acp")] + #[test] + fn test_agent_mcp_request_method_names() { + use serde_json::json; + + let params: serde_json::Map = + [("cursor".to_string(), json!("abc"))].into_iter().collect(); + + assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect"); + assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message"); + assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect"); + + assert_eq!( + AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(), + "mcp/connect" + ); + assert_eq!( + AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list")) + .method(), + "mcp/message" + ); + assert_eq!( + AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(), + "mcp/disconnect" + ); + assert_eq!( + AgentNotification::MessageMcpNotification(MessageMcpNotification::new( + "conn-1", + "notifications/progress" + )) + .method(), + "mcp/message" + ); + + assert_eq!( + serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(), + json!({ "acpId": "server-1" }) + ); + assert_eq!( + serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(), + json!({ "connectionId": "conn-1" }) + ); + assert_eq!( + serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params)) + .unwrap(), + json!({ + "connectionId": "conn-1", + "method": "tools/list", + "params": { "cursor": "abc" } + }) + ); + assert_eq!( + serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(), + json!({ "connectionId": "conn-1" }) + ); + assert_eq!( + serde_json::to_value(MessageMcpNotification::new( + "conn-1", + "notifications/progress" + )) + .unwrap(), + json!({ + "connectionId": "conn-1", + "method": "notifications/progress" + }) + ); + + let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({ + "connectionId": "conn-1", + "method": "tools/list", + "params": null + })) + .unwrap(); + assert_eq!(request_with_null_params.params, None); + } } diff --git a/src/v2/content.rs b/src/v2/content.rs index 301479c4b..a9c97d364 100644 --- a/src/v2/content.rs +++ b/src/v2/content.rs @@ -58,6 +58,14 @@ pub enum ContentBlock { /// /// Requires the `embeddedContext` prompt capability when included in prompts. Resource(EmbeddedResource), + /// A template that supports variable substitution using `{{variable_name}}` syntax. + /// + /// Allows dynamic content generation by substituting variables into template strings. + /// Variables are resolved at processing time and can include values from context, + /// user input, or system state. + /// + /// Requires the `promptVariables` prompt capability when included in prompts. + PromptTemplate(PromptTemplateContent), } /// Text provided to or from an LLM. @@ -519,6 +527,201 @@ pub enum Role { User, } +/// A template content block that supports variable substitution. +/// +/// Templates use `{{variable_name}}` syntax for variable placeholders that can be +/// substituted with actual values at processing time. This enables dynamic content +/// generation and reusable prompt templates. +#[serde_as] +#[skip_serializing_none] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[non_exhaustive] +pub struct PromptTemplateContent { + #[serde_as(deserialize_as = "DefaultOnError")] + #[serde(default)] + pub annotations: Option, + /// The template string with `{{variable_name}}` placeholders. + pub template: String, + /// Variables available for substitution in this template. + pub variables: Vec, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl PromptTemplateContent { + #[must_use] + pub fn new(template: impl Into, variables: Vec) -> Self { + Self { + annotations: None, + template: template.into(), + variables, + meta: None, + } + } + + #[must_use] + pub fn annotations(mut self, annotations: impl IntoOption) -> Self { + self.annotations = annotations.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } + + /// Substitute variables in the template and return the resolved text. + /// + /// This method processes the template string and replaces `{{variable_name}}` + /// placeholders with their corresponding values from the variables vector. + /// If a variable is not found or has no value, the placeholder is left unchanged. + #[must_use] + pub fn substitute(&self) -> String { + let mut result = self.template.clone(); + + for variable in &self.variables { + if let Some(value) = &variable.value { + let placeholder = format!("{{{{{}}}}}", variable.name); + result = result.replace(&placeholder, value); + } + } + + result + } +} + +/// A variable that can be substituted in a prompt template. +/// +/// Variables define named placeholders that can be replaced with actual values +/// during template processing. They can include metadata about expected types, +/// descriptions for user interfaces, and validation constraints. +#[serde_as] +#[skip_serializing_none] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[non_exhaustive] +pub struct PromptVariable { + /// The variable name (used in `{{variable_name}}` placeholders). + pub name: String, + /// The current value of the variable (if set). + pub value: Option, + /// Human-readable description of this variable. + pub description: Option, + /// The expected type of this variable's value. + #[serde(rename = "type")] + pub variable_type: Option, + /// Whether this variable is required for template processing. + #[serde(default)] + pub required: bool, + /// Default value to use if no value is provided. + pub default_value: Option, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl PromptVariable { + #[must_use] + pub fn new(name: impl Into) -> Self { + Self { + name: name.into(), + value: None, + description: None, + variable_type: None, + required: false, + default_value: None, + meta: None, + } + } + + #[must_use] + pub fn value(mut self, value: impl IntoOption) -> Self { + self.value = value.into_option(); + self + } + + #[must_use] + pub fn description(mut self, description: impl IntoOption) -> Self { + self.description = description.into_option(); + self + } + + #[must_use] + pub fn variable_type(mut self, variable_type: impl IntoOption) -> Self { + self.variable_type = variable_type.into_option(); + self + } + + #[must_use] + pub fn required(mut self, required: bool) -> Self { + self.required = required; + self + } + + #[must_use] + pub fn default_value(mut self, default_value: impl IntoOption) -> Self { + self.default_value = default_value.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } + + /// Get the effective value for this variable, considering default values. + #[must_use] + pub fn effective_value(&self) -> Option<&String> { + self.value.as_ref().or(self.default_value.as_ref()) + } +} + +/// The expected type of a prompt variable's value. +/// +/// This helps clients provide appropriate input interfaces and validation +/// for prompt variables. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum PromptVariableType { + /// A string value (default if not specified). + String, + /// A numeric value (integer or float). + Number, + /// A boolean value (true/false). + Boolean, + /// A date/time value in ISO 8601 format. + DateTime, + /// A URL or URI reference. + Url, + /// An email address. + Email, + /// A multiline text value. + Text, + /// A value selected from a predefined list (enum-like). + Select { options: Vec }, +} + #[cfg(test)] mod tests { use super::*; @@ -587,4 +790,159 @@ mod tests { assert!(!json.as_object().unwrap().contains_key("annotations")); assert!(!json.as_object().unwrap().contains_key("meta")); } + + #[test] + fn test_prompt_variable_creation() { + let var = PromptVariable::new("username") + .value("alice") + .description("The user's name") + .variable_type(PromptVariableType::String) + .required(true); + + assert_eq!(var.name, "username"); + assert_eq!(var.value, Some("alice".to_string())); + assert_eq!(var.description, Some("The user's name".to_string())); + assert_eq!(var.variable_type, Some(PromptVariableType::String)); + assert!(var.required); + } + + #[test] + fn test_prompt_variable_effective_value() { + // Test with value set + let var_with_value = PromptVariable::new("test") + .value("actual_value") + .default_value("default_value"); + assert_eq!( + var_with_value.effective_value(), + Some(&"actual_value".to_string()) + ); + + // Test with only default value + let var_with_default = PromptVariable::new("test").default_value("default_value"); + assert_eq!( + var_with_default.effective_value(), + Some(&"default_value".to_string()) + ); + + // Test with neither value nor default + let var_empty = PromptVariable::new("test"); + assert_eq!(var_empty.effective_value(), None); + } + + #[test] + fn test_prompt_template_substitution() { + let variables = vec![ + PromptVariable::new("name").value("Alice"), + PromptVariable::new("age").value("25"), + PromptVariable::new("city").value("New York"), + ]; + + let template = PromptTemplateContent::new( + "Hello {{name}}, you are {{age}} years old and live in {{city}}!", + variables, + ); + + let result = template.substitute(); + assert_eq!( + result, + "Hello Alice, you are 25 years old and live in New York!" + ); + } + + #[test] + fn test_prompt_template_substitution_with_missing_values() { + let variables = vec![ + PromptVariable::new("name").value("Alice"), + PromptVariable::new("age"), // No value set + ]; + + let template = + PromptTemplateContent::new("Hello {{name}}, you are {{age}} years old!", variables); + + let result = template.substitute(); + // Missing variables should remain as placeholders + assert_eq!(result, "Hello Alice, you are {{age}} years old!"); + } + + #[test] + fn test_prompt_template_substitution_with_default_values() { + let variables = vec![ + PromptVariable::new("name").value("Alice"), + PromptVariable::new("greeting").default_value("Hello"), + ]; + + let template = PromptTemplateContent::new("{{greeting}} {{name}}!", variables); + + // Note: substitute() currently only uses explicit values, not defaults + // This behavior could be enhanced to use effective_value() + let result = template.substitute(); + assert_eq!(result, "{{greeting}} Alice!"); + } + + #[test] + fn test_prompt_variable_type_serialization() { + // Test basic types + let string_type = PromptVariableType::String; + let json = serde_json::to_value(&string_type).unwrap(); + assert_eq!(json, "string"); + + let number_type = PromptVariableType::Number; + let json = serde_json::to_value(&number_type).unwrap(); + assert_eq!(json, "number"); + + // Test select type with options + let select_type = PromptVariableType::Select { + options: vec!["option1".to_string(), "option2".to_string()], + }; + let json = serde_json::to_value(&select_type).unwrap(); + assert_eq!( + json["select"]["options"], + serde_json::json!(["option1", "option2"]) + ); + } + + #[test] + fn test_content_block_prompt_template() { + let variables = vec![PromptVariable::new("user").value("Bob")]; + let template_content = PromptTemplateContent::new("Welcome {{user}}!", variables); + let content_block = ContentBlock::PromptTemplate(template_content); + + // Test serialization + let json = serde_json::to_value(&content_block).unwrap(); + assert_eq!(json["type"], "prompt_template"); + assert_eq!(json["template"], "Welcome {{user}}!"); + + // Test deserialization + let parsed: ContentBlock = serde_json::from_value(json).unwrap(); + if let ContentBlock::PromptTemplate(template) = parsed { + assert_eq!(template.template, "Welcome {{user}}!"); + assert_eq!(template.variables.len(), 1); + assert_eq!(template.variables[0].name, "user"); + } else { + panic!("Expected PromptTemplate variant"); + } + } + + #[test] + fn test_prompt_template_roundtrip() { + let variables = vec![ + PromptVariable::new("name") + .value("Test User") + .description("The name of the user") + .variable_type(PromptVariableType::String) + .required(true), + PromptVariable::new("count") + .value("5") + .variable_type(PromptVariableType::Number) + .default_value("1"), + ]; + + let original = + PromptTemplateContent::new("Hello {{name}}, you have {{count}} messages.", variables); + + let json = serde_json::to_value(&original).unwrap(); + let parsed: PromptTemplateContent = serde_json::from_value(json).unwrap(); + + assert_eq!(original, parsed); + } } diff --git a/src/v2/conversion.rs b/src/v2/conversion.rs index 0258578a3..4fad864c3 100644 --- a/src/v2/conversion.rs +++ b/src/v2/conversion.rs @@ -1688,6 +1688,220 @@ impl IntoV2 for crate::v1::TerminalExitStatus { } } +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::ConnectMcpRequest { + type Output = crate::v1::ConnectMcpRequest; + + fn into_v1(self) -> Result { + let Self { acp_id, meta } = self; + Ok(crate::v1::ConnectMcpRequest { + acp_id: acp_id.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::ConnectMcpRequest { + type Output = super::ConnectMcpRequest; + + fn into_v2(self) -> Result { + let Self { acp_id, meta } = self; + Ok(super::ConnectMcpRequest { + acp_id: acp_id.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::ConnectMcpResponse { + type Output = crate::v1::ConnectMcpResponse; + + fn into_v1(self) -> Result { + let Self { + connection_id, + meta, + } = self; + Ok(crate::v1::ConnectMcpResponse { + connection_id: connection_id.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::ConnectMcpResponse { + type Output = super::ConnectMcpResponse; + + fn into_v2(self) -> Result { + let Self { + connection_id, + meta, + } = self; + Ok(super::ConnectMcpResponse { + connection_id: connection_id.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::MessageMcpRequest { + type Output = crate::v1::MessageMcpRequest; + + fn into_v1(self) -> Result { + let Self { + connection_id, + method, + params, + meta, + } = self; + Ok(crate::v1::MessageMcpRequest { + connection_id: connection_id.into_v1()?, + method: method.into_v1()?, + params: params.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::MessageMcpRequest { + type Output = super::MessageMcpRequest; + + fn into_v2(self) -> Result { + let Self { + connection_id, + method, + params, + meta, + } = self; + Ok(super::MessageMcpRequest { + connection_id: connection_id.into_v2()?, + method: method.into_v2()?, + params: params.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::MessageMcpNotification { + type Output = crate::v1::MessageMcpNotification; + + fn into_v1(self) -> Result { + let Self { + connection_id, + method, + params, + meta, + } = self; + Ok(crate::v1::MessageMcpNotification { + connection_id: connection_id.into_v1()?, + method: method.into_v1()?, + params: params.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::MessageMcpNotification { + type Output = super::MessageMcpNotification; + + fn into_v2(self) -> Result { + let Self { + connection_id, + method, + params, + meta, + } = self; + Ok(super::MessageMcpNotification { + connection_id: connection_id.into_v2()?, + method: method.into_v2()?, + params: params.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::MessageMcpResponse { + type Output = crate::v1::MessageMcpResponse; + + fn into_v1(self) -> Result { + let Self(result) = self; + Ok(crate::v1::MessageMcpResponse::new(result.into_v1()?)) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::MessageMcpResponse { + type Output = super::MessageMcpResponse; + + fn into_v2(self) -> Result { + let Self(result) = self; + Ok(super::MessageMcpResponse::new(result.into_v2()?)) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::DisconnectMcpRequest { + type Output = crate::v1::DisconnectMcpRequest; + + fn into_v1(self) -> Result { + let Self { + connection_id, + meta, + } = self; + Ok(crate::v1::DisconnectMcpRequest { + connection_id: connection_id.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::DisconnectMcpRequest { + type Output = super::DisconnectMcpRequest; + + fn into_v2(self) -> Result { + let Self { + connection_id, + meta, + } = self; + Ok(super::DisconnectMcpRequest { + connection_id: connection_id.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::DisconnectMcpResponse { + type Output = crate::v1::DisconnectMcpResponse; + + fn into_v1(self) -> Result { + let Self { meta } = self; + Ok(crate::v1::DisconnectMcpResponse { + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::DisconnectMcpResponse { + type Output = super::DisconnectMcpResponse; + + fn into_v2(self) -> Result { + let Self { meta } = self; + Ok(super::DisconnectMcpResponse { + meta: meta.into_v2()?, + }) + } +} + impl IntoV1 for super::ClientCapabilities { type Output = crate::v1::ClientCapabilities; @@ -1847,6 +2061,18 @@ impl IntoV1 for super::AgentRequest { Self::CreateElicitationRequest(value) => { crate::v1::AgentRequest::CreateElicitationRequest(value.into_v1()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::ConnectMcpRequest(value) => { + crate::v1::AgentRequest::ConnectMcpRequest(value.into_v1()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(value) => { + crate::v1::AgentRequest::MessageMcpRequest(value.into_v1()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::DisconnectMcpRequest(value) => { + crate::v1::AgentRequest::DisconnectMcpRequest(value.into_v1()?) + } Self::ExtMethodRequest(value) => { crate::v1::AgentRequest::ExtMethodRequest(value.into_v1()?) } @@ -1887,6 +2113,18 @@ impl IntoV2 for crate::v1::AgentRequest { Self::CreateElicitationRequest(value) => { super::AgentRequest::CreateElicitationRequest(value.into_v2()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::ConnectMcpRequest(value) => { + super::AgentRequest::ConnectMcpRequest(value.into_v2()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(value) => { + super::AgentRequest::MessageMcpRequest(value.into_v2()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::DisconnectMcpRequest(value) => { + super::AgentRequest::DisconnectMcpRequest(value.into_v2()?) + } Self::ExtMethodRequest(value) => { super::AgentRequest::ExtMethodRequest(value.into_v2()?) } @@ -1927,6 +2165,18 @@ impl IntoV1 for super::ClientResponse { Self::CreateElicitationResponse(value) => { crate::v1::ClientResponse::CreateElicitationResponse(value.into_v1()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::ConnectMcpResponse(value) => { + crate::v1::ClientResponse::ConnectMcpResponse(value.into_v1()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpResponse(value) => { + crate::v1::ClientResponse::MessageMcpResponse(value.into_v1()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::DisconnectMcpResponse(value) => { + crate::v1::ClientResponse::DisconnectMcpResponse(value.into_v1()?) + } Self::ExtMethodResponse(value) => { crate::v1::ClientResponse::ExtMethodResponse(value.into_v1()?) } @@ -1967,6 +2217,18 @@ impl IntoV2 for crate::v1::ClientResponse { Self::CreateElicitationResponse(value) => { super::ClientResponse::CreateElicitationResponse(value.into_v2()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::ConnectMcpResponse(value) => { + super::ClientResponse::ConnectMcpResponse(value.into_v2()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpResponse(value) => { + super::ClientResponse::MessageMcpResponse(value.into_v2()?) + } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::DisconnectMcpResponse(value) => { + super::ClientResponse::DisconnectMcpResponse(value.into_v2()?) + } Self::ExtMethodResponse(value) => { super::ClientResponse::ExtMethodResponse(value.into_v2()?) } @@ -1986,6 +2248,10 @@ impl IntoV1 for super::AgentNotification { Self::CompleteElicitationNotification(value) => { crate::v1::AgentNotification::CompleteElicitationNotification(value.into_v1()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(value) => { + crate::v1::AgentNotification::MessageMcpNotification(value.into_v1()?) + } Self::ExtNotification(value) => { crate::v1::AgentNotification::ExtNotification(value.into_v1()?) } @@ -2005,6 +2271,10 @@ impl IntoV2 for crate::v1::AgentNotification { Self::CompleteElicitationNotification(value) => { super::AgentNotification::CompleteElicitationNotification(value.into_v2()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(value) => { + super::AgentNotification::MessageMcpNotification(value.into_v2()?) + } Self::ExtNotification(value) => { super::AgentNotification::ExtNotification(value.into_v2()?) } @@ -2648,7 +2918,6 @@ impl IntoV2 for crate::v1::AuthenticateResponse { } } -#[cfg(feature = "unstable_logout")] impl IntoV1 for super::LogoutRequest { type Output = crate::v1::LogoutRequest; @@ -2660,7 +2929,6 @@ impl IntoV1 for super::LogoutRequest { } } -#[cfg(feature = "unstable_logout")] impl IntoV2 for crate::v1::LogoutRequest { type Output = super::LogoutRequest; @@ -2672,7 +2940,6 @@ impl IntoV2 for crate::v1::LogoutRequest { } } -#[cfg(feature = "unstable_logout")] impl IntoV1 for super::LogoutResponse { type Output = crate::v1::LogoutResponse; @@ -2684,7 +2951,6 @@ impl IntoV1 for super::LogoutResponse { } } -#[cfg(feature = "unstable_logout")] impl IntoV2 for crate::v1::LogoutResponse { type Output = super::LogoutResponse; @@ -2696,7 +2962,6 @@ impl IntoV2 for crate::v1::LogoutResponse { } } -#[cfg(feature = "unstable_logout")] impl IntoV1 for super::AgentAuthCapabilities { type Output = crate::v1::AgentAuthCapabilities; @@ -2709,7 +2974,6 @@ impl IntoV1 for super::AgentAuthCapabilities { } } -#[cfg(feature = "unstable_logout")] impl IntoV2 for crate::v1::AgentAuthCapabilities { type Output = super::AgentAuthCapabilities; @@ -2722,7 +2986,6 @@ impl IntoV2 for crate::v1::AgentAuthCapabilities { } } -#[cfg(feature = "unstable_logout")] impl IntoV1 for super::LogoutCapabilities { type Output = crate::v1::LogoutCapabilities; @@ -2734,7 +2997,6 @@ impl IntoV1 for super::LogoutCapabilities { } } -#[cfg(feature = "unstable_logout")] impl IntoV2 for crate::v1::LogoutCapabilities { type Output = super::LogoutCapabilities; @@ -3374,21 +3636,63 @@ impl IntoV2 for crate::v1::CloseSessionResponse { } } +#[cfg(feature = "unstable_session_delete")] +impl IntoV1 for super::DeleteSessionRequest { + type Output = crate::v1::DeleteSessionRequest; + + fn into_v1(self) -> Result { + let Self { session_id, meta } = self; + Ok(crate::v1::DeleteSessionRequest { + session_id: session_id.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_session_delete")] +impl IntoV2 for crate::v1::DeleteSessionRequest { + type Output = super::DeleteSessionRequest; + + fn into_v2(self) -> Result { + let Self { session_id, meta } = self; + Ok(super::DeleteSessionRequest { + session_id: session_id.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +#[cfg(feature = "unstable_session_delete")] +impl IntoV1 for super::DeleteSessionResponse { + type Output = crate::v1::DeleteSessionResponse; + + fn into_v1(self) -> Result { + let Self { meta } = self; + Ok(crate::v1::DeleteSessionResponse { + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_session_delete")] +impl IntoV2 for crate::v1::DeleteSessionResponse { + type Output = super::DeleteSessionResponse; + + fn into_v2(self) -> Result { + let Self { meta } = self; + Ok(super::DeleteSessionResponse { + meta: meta.into_v2()?, + }) + } +} + impl IntoV1 for super::ListSessionsRequest { type Output = crate::v1::ListSessionsRequest; fn into_v1(self) -> Result { - let Self { - cwd, - #[cfg(feature = "unstable_session_additional_directories")] - additional_directories, - cursor, - meta, - } = self; + let Self { cwd, cursor, meta } = self; Ok(crate::v1::ListSessionsRequest { cwd: cwd.into_v1()?, - #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: additional_directories.into_v1()?, cursor: cursor.into_v1()?, meta: meta.into_v1()?, }) @@ -3399,17 +3703,9 @@ impl IntoV2 for crate::v1::ListSessionsRequest { type Output = super::ListSessionsRequest; fn into_v2(self) -> Result { - let Self { - cwd, - #[cfg(feature = "unstable_session_additional_directories")] - additional_directories, - cursor, - meta, - } = self; + let Self { cwd, cursor, meta } = self; Ok(super::ListSessionsRequest { cwd: cwd.into_v2()?, - #[cfg(feature = "unstable_session_additional_directories")] - additional_directories: additional_directories.into_v2()?, cursor: cursor.into_v2()?, meta: meta.into_v2()?, }) @@ -4053,6 +4349,8 @@ impl IntoV1 for super::McpServer { Ok(match self { Self::Http(value) => crate::v1::McpServer::Http(value.into_v1()?), Self::Sse(value) => crate::v1::McpServer::Sse(value.into_v1()?), + #[cfg(feature = "unstable_mcp_over_acp")] + Self::Acp(value) => crate::v1::McpServer::Acp(value.into_v1()?), Self::Stdio(value) => crate::v1::McpServer::Stdio(value.into_v1()?), }) } @@ -4065,6 +4363,8 @@ impl IntoV2 for crate::v1::McpServer { Ok(match self { Self::Http(value) => super::McpServer::Http(value.into_v2()?), Self::Sse(value) => super::McpServer::Sse(value.into_v2()?), + #[cfg(feature = "unstable_mcp_over_acp")] + Self::Acp(value) => super::McpServer::Acp(value.into_v2()?), Self::Stdio(value) => super::McpServer::Stdio(value.into_v2()?), }) } @@ -4146,6 +4446,70 @@ impl IntoV2 for crate::v1::McpServerSse { } } +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::McpServerAcpId { + type Output = crate::v1::McpServerAcpId; + + fn into_v1(self) -> Result { + Ok(crate::v1::McpServerAcpId(self.0.into_v1()?)) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::McpServerAcpId { + type Output = super::McpServerAcpId; + + fn into_v2(self) -> Result { + Ok(super::McpServerAcpId(self.0.into_v2()?)) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::McpConnectionId { + type Output = crate::v1::McpConnectionId; + + fn into_v1(self) -> Result { + Ok(crate::v1::McpConnectionId(self.0.into_v1()?)) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::McpConnectionId { + type Output = super::McpConnectionId; + + fn into_v2(self) -> Result { + Ok(super::McpConnectionId(self.0.into_v2()?)) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV1 for super::McpServerAcp { + type Output = crate::v1::McpServerAcp; + + fn into_v1(self) -> Result { + let Self { name, id, meta } = self; + Ok(crate::v1::McpServerAcp { + name: name.into_v1()?, + id: id.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_mcp_over_acp")] +impl IntoV2 for crate::v1::McpServerAcp { + type Output = super::McpServerAcp; + + fn into_v2(self) -> Result { + let Self { name, id, meta } = self; + Ok(super::McpServerAcp { + name: name.into_v2()?, + id: id.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + impl IntoV1 for super::McpServerStdio { type Output = crate::v1::McpServerStdio; @@ -4711,8 +5075,8 @@ impl IntoV2 for crate::v1::ListProvidersResponse { } #[cfg(feature = "unstable_llm_providers")] -impl IntoV1 for super::SetProvidersRequest { - type Output = crate::v1::SetProvidersRequest; +impl IntoV1 for super::SetProviderRequest { + type Output = crate::v1::SetProviderRequest; fn into_v1(self) -> Result { let Self { @@ -4722,7 +5086,7 @@ impl IntoV1 for super::SetProvidersRequest { headers, meta, } = self; - Ok(crate::v1::SetProvidersRequest { + Ok(crate::v1::SetProviderRequest { id: id.into_v1()?, api_type: api_type.into_v1()?, base_url: base_url.into_v1()?, @@ -4733,8 +5097,8 @@ impl IntoV1 for super::SetProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl IntoV2 for crate::v1::SetProvidersRequest { - type Output = super::SetProvidersRequest; +impl IntoV2 for crate::v1::SetProviderRequest { + type Output = super::SetProviderRequest; fn into_v2(self) -> Result { let Self { @@ -4744,7 +5108,7 @@ impl IntoV2 for crate::v1::SetProvidersRequest { headers, meta, } = self; - Ok(super::SetProvidersRequest { + Ok(super::SetProviderRequest { id: id.into_v2()?, api_type: api_type.into_v2()?, base_url: base_url.into_v2()?, @@ -4755,36 +5119,36 @@ impl IntoV2 for crate::v1::SetProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl IntoV1 for super::SetProvidersResponse { - type Output = crate::v1::SetProvidersResponse; +impl IntoV1 for super::SetProviderResponse { + type Output = crate::v1::SetProviderResponse; fn into_v1(self) -> Result { let Self { meta } = self; - Ok(crate::v1::SetProvidersResponse { + Ok(crate::v1::SetProviderResponse { meta: meta.into_v1()?, }) } } #[cfg(feature = "unstable_llm_providers")] -impl IntoV2 for crate::v1::SetProvidersResponse { - type Output = super::SetProvidersResponse; +impl IntoV2 for crate::v1::SetProviderResponse { + type Output = super::SetProviderResponse; fn into_v2(self) -> Result { let Self { meta } = self; - Ok(super::SetProvidersResponse { + Ok(super::SetProviderResponse { meta: meta.into_v2()?, }) } } #[cfg(feature = "unstable_llm_providers")] -impl IntoV1 for super::DisableProvidersRequest { - type Output = crate::v1::DisableProvidersRequest; +impl IntoV1 for super::DisableProviderRequest { + type Output = crate::v1::DisableProviderRequest; fn into_v1(self) -> Result { let Self { id, meta } = self; - Ok(crate::v1::DisableProvidersRequest { + Ok(crate::v1::DisableProviderRequest { id: id.into_v1()?, meta: meta.into_v1()?, }) @@ -4792,12 +5156,12 @@ impl IntoV1 for super::DisableProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl IntoV2 for crate::v1::DisableProvidersRequest { - type Output = super::DisableProvidersRequest; +impl IntoV2 for crate::v1::DisableProviderRequest { + type Output = super::DisableProviderRequest; fn into_v2(self) -> Result { let Self { id, meta } = self; - Ok(super::DisableProvidersRequest { + Ok(super::DisableProviderRequest { id: id.into_v2()?, meta: meta.into_v2()?, }) @@ -4805,24 +5169,24 @@ impl IntoV2 for crate::v1::DisableProvidersRequest { } #[cfg(feature = "unstable_llm_providers")] -impl IntoV1 for super::DisableProvidersResponse { - type Output = crate::v1::DisableProvidersResponse; +impl IntoV1 for super::DisableProviderResponse { + type Output = crate::v1::DisableProviderResponse; fn into_v1(self) -> Result { let Self { meta } = self; - Ok(crate::v1::DisableProvidersResponse { + Ok(crate::v1::DisableProviderResponse { meta: meta.into_v1()?, }) } } #[cfg(feature = "unstable_llm_providers")] -impl IntoV2 for crate::v1::DisableProvidersResponse { - type Output = super::DisableProvidersResponse; +impl IntoV2 for crate::v1::DisableProviderResponse { + type Output = super::DisableProviderResponse; fn into_v2(self) -> Result { let Self { meta } = self; - Ok(super::DisableProvidersResponse { + Ok(super::DisableProviderResponse { meta: meta.into_v2()?, }) } @@ -4837,7 +5201,6 @@ impl IntoV1 for super::AgentCapabilities { prompt_capabilities, mcp_capabilities, session_capabilities, - #[cfg(feature = "unstable_logout")] auth, #[cfg(feature = "unstable_llm_providers")] providers, @@ -4852,7 +5215,6 @@ impl IntoV1 for super::AgentCapabilities { prompt_capabilities: prompt_capabilities.into_v1()?, mcp_capabilities: mcp_capabilities.into_v1()?, session_capabilities: session_capabilities.into_v1()?, - #[cfg(feature = "unstable_logout")] auth: auth.into_v1()?, #[cfg(feature = "unstable_llm_providers")] providers: providers.into_v1()?, @@ -4874,7 +5236,6 @@ impl IntoV2 for crate::v1::AgentCapabilities { prompt_capabilities, mcp_capabilities, session_capabilities, - #[cfg(feature = "unstable_logout")] auth, #[cfg(feature = "unstable_llm_providers")] providers, @@ -4889,7 +5250,6 @@ impl IntoV2 for crate::v1::AgentCapabilities { prompt_capabilities: prompt_capabilities.into_v2()?, mcp_capabilities: mcp_capabilities.into_v2()?, session_capabilities: session_capabilities.into_v2()?, - #[cfg(feature = "unstable_logout")] auth: auth.into_v2()?, #[cfg(feature = "unstable_llm_providers")] providers: providers.into_v2()?, @@ -4932,6 +5292,8 @@ impl IntoV1 for super::SessionCapabilities { fn into_v1(self) -> Result { let Self { list, + #[cfg(feature = "unstable_session_delete")] + delete, #[cfg(feature = "unstable_session_additional_directories")] additional_directories, #[cfg(feature = "unstable_session_fork")] @@ -4942,6 +5304,8 @@ impl IntoV1 for super::SessionCapabilities { } = self; Ok(crate::v1::SessionCapabilities { list: list.into_v1()?, + #[cfg(feature = "unstable_session_delete")] + delete: delete.into_v1()?, #[cfg(feature = "unstable_session_additional_directories")] additional_directories: additional_directories.into_v1()?, #[cfg(feature = "unstable_session_fork")] @@ -4959,6 +5323,8 @@ impl IntoV2 for crate::v1::SessionCapabilities { fn into_v2(self) -> Result { let Self { list, + #[cfg(feature = "unstable_session_delete")] + delete, #[cfg(feature = "unstable_session_additional_directories")] additional_directories, #[cfg(feature = "unstable_session_fork")] @@ -4969,6 +5335,8 @@ impl IntoV2 for crate::v1::SessionCapabilities { } = self; Ok(super::SessionCapabilities { list: list.into_v2()?, + #[cfg(feature = "unstable_session_delete")] + delete: delete.into_v2()?, #[cfg(feature = "unstable_session_additional_directories")] additional_directories: additional_directories.into_v2()?, #[cfg(feature = "unstable_session_fork")] @@ -5002,6 +5370,30 @@ impl IntoV2 for crate::v1::SessionListCapabilities { } } +#[cfg(feature = "unstable_session_delete")] +impl IntoV1 for super::SessionDeleteCapabilities { + type Output = crate::v1::SessionDeleteCapabilities; + + fn into_v1(self) -> Result { + let Self { meta } = self; + Ok(crate::v1::SessionDeleteCapabilities { + meta: meta.into_v1()?, + }) + } +} + +#[cfg(feature = "unstable_session_delete")] +impl IntoV2 for crate::v1::SessionDeleteCapabilities { + type Output = super::SessionDeleteCapabilities; + + fn into_v2(self) -> Result { + let Self { meta } = self; + Ok(super::SessionDeleteCapabilities { + meta: meta.into_v2()?, + }) + } +} + #[cfg(feature = "unstable_session_additional_directories")] impl IntoV1 for super::SessionAdditionalDirectoriesCapabilities { type Output = crate::v1::SessionAdditionalDirectoriesCapabilities; @@ -5102,12 +5494,14 @@ impl IntoV1 for super::PromptCapabilities { image, audio, embedded_context, + prompt_variables, meta, } = self; Ok(crate::v1::PromptCapabilities { image: image.into_v1()?, audio: audio.into_v1()?, embedded_context: embedded_context.into_v1()?, + prompt_variables: prompt_variables.into_v1()?, meta: meta.into_v1()?, }) } @@ -5121,12 +5515,14 @@ impl IntoV2 for crate::v1::PromptCapabilities { image, audio, embedded_context, + prompt_variables, meta, } = self; Ok(super::PromptCapabilities { image: image.into_v2()?, audio: audio.into_v2()?, embedded_context: embedded_context.into_v2()?, + prompt_variables: prompt_variables.into_v2()?, meta: meta.into_v2()?, }) } @@ -5136,10 +5532,18 @@ impl IntoV1 for super::McpCapabilities { type Output = crate::v1::McpCapabilities; fn into_v1(self) -> Result { - let Self { http, sse, meta } = self; + let Self { + http, + sse, + #[cfg(feature = "unstable_mcp_over_acp")] + acp, + meta, + } = self; Ok(crate::v1::McpCapabilities { http: http.into_v1()?, sse: sse.into_v1()?, + #[cfg(feature = "unstable_mcp_over_acp")] + acp: acp.into_v1()?, meta: meta.into_v1()?, }) } @@ -5149,10 +5553,18 @@ impl IntoV2 for crate::v1::McpCapabilities { type Output = super::McpCapabilities; fn into_v2(self) -> Result { - let Self { http, sse, meta } = self; + let Self { + http, + sse, + #[cfg(feature = "unstable_mcp_over_acp")] + acp, + meta, + } = self; Ok(super::McpCapabilities { http: http.into_v2()?, sse: sse.into_v2()?, + #[cfg(feature = "unstable_mcp_over_acp")] + acp: acp.into_v2()?, meta: meta.into_v2()?, }) } @@ -5174,14 +5586,13 @@ impl IntoV1 for super::ClientRequest { crate::v1::ClientRequest::ListProvidersRequest(value.into_v1()?) } #[cfg(feature = "unstable_llm_providers")] - Self::SetProvidersRequest(value) => { - crate::v1::ClientRequest::SetProvidersRequest(value.into_v1()?) + Self::SetProviderRequest(value) => { + crate::v1::ClientRequest::SetProviderRequest(value.into_v1()?) } #[cfg(feature = "unstable_llm_providers")] - Self::DisableProvidersRequest(value) => { - crate::v1::ClientRequest::DisableProvidersRequest(value.into_v1()?) + Self::DisableProviderRequest(value) => { + crate::v1::ClientRequest::DisableProviderRequest(value.into_v1()?) } - #[cfg(feature = "unstable_logout")] Self::LogoutRequest(value) => crate::v1::ClientRequest::LogoutRequest(value.into_v1()?), Self::NewSessionRequest(value) => { crate::v1::ClientRequest::NewSessionRequest(value.into_v1()?) @@ -5192,6 +5603,10 @@ impl IntoV1 for super::ClientRequest { Self::ListSessionsRequest(value) => { crate::v1::ClientRequest::ListSessionsRequest(value.into_v1()?) } + #[cfg(feature = "unstable_session_delete")] + Self::DeleteSessionRequest(value) => { + crate::v1::ClientRequest::DeleteSessionRequest(value.into_v1()?) + } #[cfg(feature = "unstable_session_fork")] Self::ForkSessionRequest(value) => { crate::v1::ClientRequest::ForkSessionRequest(value.into_v1()?) @@ -5225,6 +5640,10 @@ impl IntoV1 for super::ClientRequest { Self::CloseNesRequest(value) => { crate::v1::ClientRequest::CloseNesRequest(value.into_v1()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(value) => { + crate::v1::ClientRequest::MessageMcpRequest(value.into_v1()?) + } Self::ExtMethodRequest(value) => { crate::v1::ClientRequest::ExtMethodRequest(value.into_v1()?) } @@ -5248,14 +5667,13 @@ impl IntoV2 for crate::v1::ClientRequest { super::ClientRequest::ListProvidersRequest(value.into_v2()?) } #[cfg(feature = "unstable_llm_providers")] - Self::SetProvidersRequest(value) => { - super::ClientRequest::SetProvidersRequest(value.into_v2()?) + Self::SetProviderRequest(value) => { + super::ClientRequest::SetProviderRequest(value.into_v2()?) } #[cfg(feature = "unstable_llm_providers")] - Self::DisableProvidersRequest(value) => { - super::ClientRequest::DisableProvidersRequest(value.into_v2()?) + Self::DisableProviderRequest(value) => { + super::ClientRequest::DisableProviderRequest(value.into_v2()?) } - #[cfg(feature = "unstable_logout")] Self::LogoutRequest(value) => super::ClientRequest::LogoutRequest(value.into_v2()?), Self::NewSessionRequest(value) => { super::ClientRequest::NewSessionRequest(value.into_v2()?) @@ -5266,6 +5684,10 @@ impl IntoV2 for crate::v1::ClientRequest { Self::ListSessionsRequest(value) => { super::ClientRequest::ListSessionsRequest(value.into_v2()?) } + #[cfg(feature = "unstable_session_delete")] + Self::DeleteSessionRequest(value) => { + super::ClientRequest::DeleteSessionRequest(value.into_v2()?) + } #[cfg(feature = "unstable_session_fork")] Self::ForkSessionRequest(value) => { super::ClientRequest::ForkSessionRequest(value.into_v2()?) @@ -5295,6 +5717,10 @@ impl IntoV2 for crate::v1::ClientRequest { } #[cfg(feature = "unstable_nes")] Self::CloseNesRequest(value) => super::ClientRequest::CloseNesRequest(value.into_v2()?), + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpRequest(value) => { + super::ClientRequest::MessageMcpRequest(value.into_v2()?) + } Self::ExtMethodRequest(value) => { super::ClientRequest::ExtMethodRequest(value.into_v2()?) } @@ -5318,14 +5744,13 @@ impl IntoV1 for super::AgentResponse { crate::v1::AgentResponse::ListProvidersResponse(value.into_v1()?) } #[cfg(feature = "unstable_llm_providers")] - Self::SetProvidersResponse(value) => { - crate::v1::AgentResponse::SetProvidersResponse(value.into_v1()?) + Self::SetProviderResponse(value) => { + crate::v1::AgentResponse::SetProviderResponse(value.into_v1()?) } #[cfg(feature = "unstable_llm_providers")] - Self::DisableProvidersResponse(value) => { - crate::v1::AgentResponse::DisableProvidersResponse(value.into_v1()?) + Self::DisableProviderResponse(value) => { + crate::v1::AgentResponse::DisableProviderResponse(value.into_v1()?) } - #[cfg(feature = "unstable_logout")] Self::LogoutResponse(value) => { crate::v1::AgentResponse::LogoutResponse(value.into_v1()?) } @@ -5338,6 +5763,10 @@ impl IntoV1 for super::AgentResponse { Self::ListSessionsResponse(value) => { crate::v1::AgentResponse::ListSessionsResponse(value.into_v1()?) } + #[cfg(feature = "unstable_session_delete")] + Self::DeleteSessionResponse(value) => { + crate::v1::AgentResponse::DeleteSessionResponse(value.into_v1()?) + } #[cfg(feature = "unstable_session_fork")] Self::ForkSessionResponse(value) => { crate::v1::AgentResponse::ForkSessionResponse(value.into_v1()?) @@ -5376,6 +5805,10 @@ impl IntoV1 for super::AgentResponse { Self::ExtMethodResponse(value) => { crate::v1::AgentResponse::ExtMethodResponse(value.into_v1()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpResponse(value) => { + crate::v1::AgentResponse::MessageMcpResponse(value.into_v1()?) + } }) } } @@ -5396,14 +5829,13 @@ impl IntoV2 for crate::v1::AgentResponse { super::AgentResponse::ListProvidersResponse(value.into_v2()?) } #[cfg(feature = "unstable_llm_providers")] - Self::SetProvidersResponse(value) => { - super::AgentResponse::SetProvidersResponse(value.into_v2()?) + Self::SetProviderResponse(value) => { + super::AgentResponse::SetProviderResponse(value.into_v2()?) } #[cfg(feature = "unstable_llm_providers")] - Self::DisableProvidersResponse(value) => { - super::AgentResponse::DisableProvidersResponse(value.into_v2()?) + Self::DisableProviderResponse(value) => { + super::AgentResponse::DisableProviderResponse(value.into_v2()?) } - #[cfg(feature = "unstable_logout")] Self::LogoutResponse(value) => super::AgentResponse::LogoutResponse(value.into_v2()?), Self::NewSessionResponse(value) => { super::AgentResponse::NewSessionResponse(value.into_v2()?) @@ -5414,6 +5846,10 @@ impl IntoV2 for crate::v1::AgentResponse { Self::ListSessionsResponse(value) => { super::AgentResponse::ListSessionsResponse(value.into_v2()?) } + #[cfg(feature = "unstable_session_delete")] + Self::DeleteSessionResponse(value) => { + super::AgentResponse::DeleteSessionResponse(value.into_v2()?) + } #[cfg(feature = "unstable_session_fork")] Self::ForkSessionResponse(value) => { super::AgentResponse::ForkSessionResponse(value.into_v2()?) @@ -5450,6 +5886,10 @@ impl IntoV2 for crate::v1::AgentResponse { Self::ExtMethodResponse(value) => { super::AgentResponse::ExtMethodResponse(value.into_v2()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpResponse(value) => { + super::AgentResponse::MessageMcpResponse(value.into_v2()?) + } }) } } @@ -5490,6 +5930,10 @@ impl IntoV1 for super::ClientNotification { Self::RejectNesNotification(value) => { crate::v1::ClientNotification::RejectNesNotification(value.into_v1()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(value) => { + crate::v1::ClientNotification::MessageMcpNotification(value.into_v1()?) + } Self::ExtNotification(value) => { crate::v1::ClientNotification::ExtNotification(value.into_v1()?) } @@ -5533,6 +5977,10 @@ impl IntoV2 for crate::v1::ClientNotification { Self::RejectNesNotification(value) => { super::ClientNotification::RejectNesNotification(value.into_v2()?) } + #[cfg(feature = "unstable_mcp_over_acp")] + Self::MessageMcpNotification(value) => { + super::ClientNotification::MessageMcpNotification(value.into_v2()?) + } Self::ExtNotification(value) => { super::ClientNotification::ExtNotification(value.into_v2()?) } @@ -8392,6 +8840,9 @@ impl IntoV1 for super::ContentBlock { Self::Audio(value) => crate::v1::ContentBlock::Audio(value.into_v1()?), Self::ResourceLink(value) => crate::v1::ContentBlock::ResourceLink(value.into_v1()?), Self::Resource(value) => crate::v1::ContentBlock::Resource(value.into_v1()?), + Self::PromptTemplate(value) => { + crate::v1::ContentBlock::PromptTemplate(value.into_v1()?) + } }) } } @@ -8406,6 +8857,7 @@ impl IntoV2 for crate::v1::ContentBlock { Self::Audio(value) => super::ContentBlock::Audio(value.into_v2()?), Self::ResourceLink(value) => super::ContentBlock::ResourceLink(value.into_v2()?), Self::Resource(value) => super::ContentBlock::Resource(value.into_v2()?), + Self::PromptTemplate(value) => super::ContentBlock::PromptTemplate(value.into_v2()?), }) } } @@ -8778,6 +9230,132 @@ impl IntoV2 for crate::v1::Role { } } +impl IntoV1 for super::PromptTemplateContent { + type Output = crate::v1::PromptTemplateContent; + + fn into_v1(self) -> Result { + let Self { + annotations, + template, + variables, + meta, + } = self; + Ok(crate::v1::PromptTemplateContent { + annotations: annotations.into_v1()?, + template: template.into_v1()?, + variables: variables.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +impl IntoV2 for crate::v1::PromptTemplateContent { + type Output = super::PromptTemplateContent; + + fn into_v2(self) -> Result { + let Self { + annotations, + template, + variables, + meta, + } = self; + Ok(super::PromptTemplateContent { + annotations: annotations.into_v2()?, + template: template.into_v2()?, + variables: variables.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +impl IntoV1 for super::PromptVariable { + type Output = crate::v1::PromptVariable; + + fn into_v1(self) -> Result { + let Self { + name, + value, + description, + variable_type, + required, + default_value, + meta, + } = self; + Ok(crate::v1::PromptVariable { + name: name.into_v1()?, + value: value.into_v1()?, + description: description.into_v1()?, + variable_type: variable_type.into_v1()?, + required: required.into_v1()?, + default_value: default_value.into_v1()?, + meta: meta.into_v1()?, + }) + } +} + +impl IntoV2 for crate::v1::PromptVariable { + type Output = super::PromptVariable; + + fn into_v2(self) -> Result { + let Self { + name, + value, + description, + variable_type, + required, + default_value, + meta, + } = self; + Ok(super::PromptVariable { + name: name.into_v2()?, + value: value.into_v2()?, + description: description.into_v2()?, + variable_type: variable_type.into_v2()?, + required: required.into_v2()?, + default_value: default_value.into_v2()?, + meta: meta.into_v2()?, + }) + } +} + +impl IntoV1 for super::PromptVariableType { + type Output = crate::v1::PromptVariableType; + + fn into_v1(self) -> Result { + Ok(match self { + Self::String => crate::v1::PromptVariableType::String, + Self::Number => crate::v1::PromptVariableType::Number, + Self::Boolean => crate::v1::PromptVariableType::Boolean, + Self::DateTime => crate::v1::PromptVariableType::DateTime, + Self::Url => crate::v1::PromptVariableType::Url, + Self::Email => crate::v1::PromptVariableType::Email, + Self::Text => crate::v1::PromptVariableType::Text, + Self::Select { options } => crate::v1::PromptVariableType::Select { + options: options.into_v1()?, + }, + }) + } +} + +impl IntoV2 for crate::v1::PromptVariableType { + type Output = super::PromptVariableType; + + fn into_v2(self) -> Result { + Ok(match self { + Self::String => super::PromptVariableType::String, + Self::Number => super::PromptVariableType::Number, + Self::Boolean => super::PromptVariableType::Boolean, + Self::DateTime => super::PromptVariableType::DateTime, + Self::Url => super::PromptVariableType::Url, + Self::Email => super::PromptVariableType::Email, + Self::Text => super::PromptVariableType::Text, + Self::Select { options } => super::PromptVariableType::Select { + options: options.into_v2()?, + }, + }) + } +} + #[cfg(test)] mod tests { use super::*; @@ -9023,6 +9601,82 @@ mod tests { assert_json_eq_after_v2_to_v1::(request); } + #[test] + fn round_trips_prompt_template_content() { + let variables = vec![ + v1::PromptVariable::new("name").value("Alice"), + v1::PromptVariable::new("task") + .value("testing") + .description("The task to perform") + .variable_type(v1::PromptVariableType::String) + .required(true), + ]; + let template = + v1::PromptTemplateContent::new("Hello {{name}}, let's do some {{task}}!", variables); + + assert_v1_round_trip::( + template.clone(), + ); + assert_json_eq_after_v1_to_v2::( + template, + ); + } + + #[test] + fn round_trips_prompt_variable_types() { + let test_types = vec![ + v2::PromptVariableType::String, + v2::PromptVariableType::Number, + v2::PromptVariableType::Boolean, + v2::PromptVariableType::DateTime, + v2::PromptVariableType::Url, + v2::PromptVariableType::Email, + v2::PromptVariableType::Text, + v2::PromptVariableType::Select { + options: vec!["option1".to_string(), "option2".to_string()], + }, + ]; + + for var_type in test_types { + assert_v2_round_trip::( + var_type.clone(), + ); + assert_json_eq_after_v2_to_v1::( + var_type, + ); + } + } + + #[test] + fn round_trips_prompt_capabilities_with_variables() { + let capabilities = v1::PromptCapabilities::new() + .image(true) + .audio(false) + .embedded_context(true) + .prompt_variables(true); + + assert_v1_round_trip::( + capabilities.clone(), + ); + assert_json_eq_after_v1_to_v2::( + capabilities, + ); + } + + #[test] + fn round_trips_content_block_with_prompt_template() { + let variables = vec![ + v2::PromptVariable::new("user").value("Bob"), + v2::PromptVariable::new("action").value("review"), + ]; + let template = + v2::PromptTemplateContent::new("{{user}} needs to {{action}} this code", variables); + let content_block = v2::ContentBlock::PromptTemplate(template); + + assert_v2_round_trip::(content_block.clone()); + assert_json_eq_after_v2_to_v1::(content_block); + } + #[test] fn protocol_version_v1_constant_is_unchanged_by_feature_flag() { // Guards against `LATEST` accidentally being re-pointed to V2 in the diff --git a/src/v2/mcp.rs b/src/v2/mcp.rs new file mode 100644 index 000000000..7f5ea2ce8 --- /dev/null +++ b/src/v2/mcp.rs @@ -0,0 +1,355 @@ +//! MCP-over-ACP transport types. + +use std::sync::Arc; + +use derive_more::{Display, From}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::value::RawValue; +use serde_with::skip_serializing_none; + +use super::{McpServerAcpId, Meta}; +use crate::IntoOption; + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// A unique identifier for an active MCP-over-ACP connection. +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)] +#[serde(transparent)] +#[from(Arc, String, &'static str)] +#[non_exhaustive] +pub struct McpConnectionId(pub Arc); + +impl McpConnectionId { + #[must_use] + pub fn new(id: impl Into>) -> Self { + Self(id.into()) + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for `mcp/connect`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct ConnectMcpRequest { + /// The ACP MCP server ID that was provided by the component declaring the MCP server. + pub acp_id: McpServerAcpId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl ConnectMcpRequest { + #[must_use] + pub fn new(acp_id: impl Into) -> Self { + Self { + acp_id: acp_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `mcp/connect`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_CONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct ConnectMcpResponse { + /// The unique identifier for this MCP-over-ACP connection. + pub connection_id: McpConnectionId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl ConnectMcpResponse { + #[must_use] + pub fn new(connection_id: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for `mcp/message`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))] +#[non_exhaustive] +pub struct MessageMcpRequest { + /// The MCP-over-ACP connection this message is sent on. + pub connection_id: McpConnectionId, + /// The inner MCP method name. + pub method: String, + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[serde(default)] + pub params: Option>, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl MessageMcpRequest { + #[must_use] + pub fn new(connection_id: impl Into, method: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + method: method.into(), + params: None, + meta: None, + } + } + + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[must_use] + pub fn params( + mut self, + params: impl IntoOption>, + ) -> Self { + self.params = params.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Notification parameters for `mcp/message`. +/// +/// This is used when the wrapped MCP message is a notification and the outer JSON-RPC +/// envelope has no `id`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))] +#[non_exhaustive] +pub struct MessageMcpNotification { + /// The MCP-over-ACP connection this message is sent on. + pub connection_id: McpConnectionId, + /// The inner MCP method name. + pub method: String, + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[serde(default)] + pub params: Option>, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl MessageMcpNotification { + #[must_use] + pub fn new(connection_id: impl Into, method: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + method: method.into(), + params: None, + meta: None, + } + } + + /// Optional inner MCP params. + /// + /// If omitted or set to `null`, the inner MCP message has no params. + #[must_use] + pub fn params( + mut self, + params: impl IntoOption>, + ) -> Self { + self.params = params.into_option(); + self + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `mcp/message`. +/// +/// This is the inner MCP response result payload. Any JSON value is valid. +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, From)] +#[serde(transparent)] +#[schemars(extend("x-side" = "both", "x-method" = MCP_MESSAGE_METHOD_NAME))] +#[non_exhaustive] +pub struct MessageMcpResponse(#[schemars(with = "serde_json::Value")] pub Arc); + +impl MessageMcpResponse { + #[must_use] + pub fn new(result: Arc) -> Self { + Self(result) + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Request parameters for `mcp/disconnect`. +#[skip_serializing_none] +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct DisconnectMcpRequest { + /// The MCP-over-ACP connection to close. + pub connection_id: McpConnectionId, + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl DisconnectMcpRequest { + #[must_use] + pub fn new(connection_id: impl Into) -> Self { + Self { + connection_id: connection_id.into(), + meta: None, + } + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// **UNSTABLE** +/// +/// This capability is not part of the spec yet, and may be removed or changed at any point. +/// +/// Response to `mcp/disconnect`. +#[skip_serializing_none] +#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +#[schemars(extend("x-side" = "client", "x-method" = MCP_DISCONNECT_METHOD_NAME))] +#[non_exhaustive] +pub struct DisconnectMcpResponse { + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[serde(rename = "_meta")] + pub meta: Option, +} + +impl DisconnectMcpResponse { + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// The _meta property is reserved by ACP to allow clients and agents to attach additional + /// metadata to their interactions. Implementations MUST NOT make assumptions about values at + /// these keys. + /// + /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) + #[must_use] + pub fn meta(mut self, meta: impl IntoOption) -> Self { + self.meta = meta.into_option(); + self + } +} + +/// Method name for opening an MCP-over-ACP connection. +pub(crate) const MCP_CONNECT_METHOD_NAME: &str = "mcp/connect"; +/// Method name for exchanging MCP-over-ACP messages. +pub(crate) const MCP_MESSAGE_METHOD_NAME: &str = "mcp/message"; +/// Method name for closing an MCP-over-ACP connection. +pub(crate) const MCP_DISCONNECT_METHOD_NAME: &str = "mcp/disconnect"; diff --git a/src/v2/mod.rs b/src/v2/mod.rs index 218d91fb8..ae2fda017 100644 --- a/src/v2/mod.rs +++ b/src/v2/mod.rs @@ -18,6 +18,8 @@ pub mod conversion; mod elicitation; mod error; mod ext; +#[cfg(feature = "unstable_mcp_over_acp")] +mod mcp; #[cfg(feature = "unstable_nes")] mod nes; mod plan; @@ -34,6 +36,8 @@ use derive_more::{Display, From}; pub use elicitation::*; pub use error::*; pub use ext::*; +#[cfg(feature = "unstable_mcp_over_acp")] +pub use mcp::*; #[cfg(feature = "unstable_nes")] pub use nes::*; pub use plan::*;